diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 5b2cc3e6aa..eaa3d1625f 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -3,7 +3,7 @@ menuconfig BT_ENABLED help Select this option to enable Bluetooth and show the submenu with Bluetooth configuration choices. -config BLUEDROID_ENABLED +menuconfig BLUEDROID_ENABLED bool "Bluedroid Bluetooth stack enabled" depends on BT_ENABLED default y @@ -12,25 +12,30 @@ config BLUEDROID_ENABLED config BTC_TASK_STACK_SIZE int "Bluetooth event (callback to application) task stack size" - depends on BT_ENABLED + depends on BLUEDROID_ENABLED default 3072 help This select btc task stack size config BLUEDROID_MEM_DEBUG bool "Bluedroid memory debug" - depends on BT_ENABLED + depends on BLUEDROID_ENABLED default n help Bluedroid memory debug +config CLASSIC_BT_ENABLED + bool "Classic Bluetooth" + depends on BLUEDROID_ENABLED + default n + config BT_DRAM_RELEASE bool "Release DRAM from Classic BT controller" - depends on BT_ENABLED + depends on BT_ENABLED && (!BLUEDROID_ENABLED || (BLUEDROID_ENABLED && !CLASSIC_BT_ENABLED)) default n help This option should only be used when BLE only. - Open this option will release about 30K DRAM from Classic BT. + Enabling this option will release about 30K DRAM from Classic BT. The released DRAM will be used as system heap memory. #disable now for app cpu due to a known issue @@ -49,7 +54,7 @@ config BTDM_CONTROLLER_RUN_CPU menuconfig BT_HCI_UART bool "HCI use UART as IO" - depends on BT_ENABLED + depends on BT_ENABLED && !BLUEDROID_ENABLED default n help Default HCI use VHCI, if this option choose, HCI will use UART(0/1/2) as IO. diff --git a/components/bt/bluedroid/api/esp_a2dp_api.c b/components/bt/bluedroid/api/esp_a2dp_api.c new file mode 100644 index 0000000000..cb635908c2 --- /dev/null +++ b/components/bt/bluedroid/api/esp_a2dp_api.c @@ -0,0 +1,133 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "bt_target.h" +#include +#include "esp_err.h" +#include "esp_a2dp_api.h" +#include "esp_bt_main.h" +#include "btc_manage.h" +#include "btc_av.h" + +#if BTC_AV_INCLUDED + +esp_err_t esp_a2d_register_callback(esp_a2d_cb_t callback) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (callback == NULL) { + return ESP_FAIL; + } + + btc_profile_cb_set(BTC_PID_A2DP, callback); + return ESP_OK; +} + +esp_err_t esp_a2d_sink_init(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_A2DP; + msg.act = BTC_AV_SINK_API_INIT_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_a2d_sink_deinit(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_A2DP; + msg.act = BTC_AV_SINK_API_DEINIT_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_a2d_register_data_callback(esp_a2d_data_cb_t callback) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_A2DP; + msg.act = BTC_AV_SINK_API_REG_DATA_CB_EVT; + + btc_av_args_t arg; + memset(&arg, 0, sizeof(btc_av_args_t)); + arg.data_cb = callback; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_msg_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_a2d_sink_connect(esp_bd_addr_t remote_bda) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + bt_status_t stat; + btc_av_args_t arg; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_A2DP; + msg.act = BTC_AV_SINK_API_CONNECT_EVT; + + memset(&arg, 0, sizeof(btc_av_args_t)); + + /* Switch to BTC context */ + memcpy(&(arg.connect), remote_bda, sizeof(bt_bdaddr_t)); + stat = btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_a2d_sink_disconnect(esp_bd_addr_t remote_bda) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + bt_status_t stat; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_A2DP; + msg.act = BTC_AV_SINK_API_DISCONNECT_EVT; + + /* Switch to BTC context */ + stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +#endif /* #if BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/api/esp_avrc_api.c b/components/bt/bluedroid/api/esp_avrc_api.c new file mode 100644 index 0000000000..cf4a8e003d --- /dev/null +++ b/components/bt/bluedroid/api/esp_avrc_api.c @@ -0,0 +1,96 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "bt_target.h" +#include +#include "esp_err.h" +#include "esp_avrc_api.h" +#include "esp_bt_main.h" +#include "btc_manage.h" +#include "btc_avrc.h" + +#if BTC_AV_INCLUDED + +esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (callback == NULL) { + return ESP_FAIL; + } + + btc_profile_cb_set(BTC_PID_AVRC, callback); + return ESP_OK; +} + +esp_err_t esp_avrc_ct_init(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_AVRC; + msg.act = BTC_AVRC_CTRL_API_INIT_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_avrc_ct_deinit(void) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_AVRC; + msg.act = BTC_AVRC_CTRL_API_DEINIT_EVT; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, NULL, 0, NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state) +{ + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + btc_msg_t msg; + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_AVRC; + msg.act = BTC_AVRC_CTRL_API_SND_PTCMD_EVT; + + btc_avrc_args_t arg; + memset(&arg, 0, sizeof(btc_avrc_args_t)); + + arg.pt_cmd.tl = tl; + arg.pt_cmd.key_code = key_code; + arg.pt_cmd.key_state = key_state; + + /* Switch to BTC context */ + bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_avrc_args_t), NULL); + return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL; +} + +#endif /* #if BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/api/esp_bt_device.c b/components/bt/bluedroid/api/esp_bt_device.c index dffcbe80b2..b4885cc0ef 100644 --- a/components/bt/bluedroid/api/esp_bt_device.c +++ b/components/bt/bluedroid/api/esp_bt_device.c @@ -12,10 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. - +#include +#include #include "esp_bt_device.h" #include "esp_bt_main.h" #include "controller.h" +#include "btc_task.h" +#include "btc_dev.h" const uint8_t *esp_bt_dev_get_address(void) { @@ -24,3 +27,24 @@ const uint8_t *esp_bt_dev_get_address(void) } return controller_get_interface()->get_address()->address; } + +esp_err_t esp_bt_dev_set_device_name(const char *name) +{ + btc_msg_t msg; + btc_dev_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + if (strlen(name) > ESP_DEV_DEVICE_NAME_MAX) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DEV; + msg.act = BTC_DEV_ACT_SET_DEVICE_NAME; + strcpy(arg.set_dev_name.device_name, name); + + return (btc_transfer_context(&msg, &arg, sizeof(btc_dev_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} diff --git a/components/bt/bluedroid/api/esp_gap_ble_api.c b/components/bt/bluedroid/api/esp_gap_ble_api.c index 2807281aed..a89b7da2cd 100644 --- a/components/bt/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/bluedroid/api/esp_gap_ble_api.c @@ -13,7 +13,7 @@ // limitations under the License. #include - +#include "esp_bt_device.h" #include "esp_bt_main.h" #include "esp_gap_ble_api.h" #include "bta_api.h" @@ -217,23 +217,7 @@ esp_err_t esp_ble_gap_config_local_privacy (bool privacy_enable) esp_err_t esp_ble_gap_set_device_name(const char *name) { - btc_msg_t msg; - btc_ble_gap_args_t arg; - - if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { - return ESP_ERR_INVALID_STATE; - } - - if (strlen(name) > ESP_GAP_DEVICE_NAME_MAX) { - return ESP_ERR_INVALID_ARG; - } - - msg.sig = BTC_SIG_API_CALL; - msg.pid = BTC_PID_GAP_BLE; - msg.act = BTC_GAP_BLE_ACT_SET_DEV_NAME; - strcpy(arg.set_dev_name.device_name, name); - - return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); + return esp_bt_dev_set_device_name(name); } uint8_t *esp_ble_resolve_adv_data( uint8_t *adv_data, uint8_t type, uint8_t *length) diff --git a/components/bt/bluedroid/api/esp_gap_bt_api.c b/components/bt/bluedroid/api/esp_gap_bt_api.c new file mode 100644 index 0000000000..1f68879663 --- /dev/null +++ b/components/bt/bluedroid/api/esp_gap_bt_api.c @@ -0,0 +1,42 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "bt_target.h" +#include +#include "esp_bt_main.h" +#include "esp_gap_bt_api.h" +#include "bt_trace.h" +#include "btc_manage.h" +#include "btc_gap_bt.h" + +#if BTC_GAP_BT_INCLUDED + +esp_err_t esp_bt_gap_set_scan_mode(esp_bt_scan_mode_t mode) +{ + btc_msg_t msg; + btc_gap_bt_args_t arg; + + if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) { + return ESP_ERR_INVALID_STATE; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BT; + msg.act = BTC_GAP_BT_ACT_SET_SCAN_MODE; + arg.set_scan_mode.mode = mode; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_gap_bt_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +#endif /* #if BTC_GAP_BT_INCLUDED */ diff --git a/components/bt/bluedroid/api/include/esp_a2dp_api.h b/components/bt/bluedroid/api/include/esp_a2dp_api.h new file mode 100644 index 0000000000..7f6868dde1 --- /dev/null +++ b/components/bt/bluedroid/api/include/esp_a2dp_api.h @@ -0,0 +1,216 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __ESP_A2DP_API_H__ +#define __ESP_A2DP_API_H__ + +#include "esp_err.h" +#include "esp_bt_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Media codec types supported by A2DP +#define ESP_A2D_MCT_SBC (0) /*!< SBC */ +#define ESP_A2D_MCT_M12 (0x01) /*!< MPEG-1, 2 Audio */ +#define ESP_A2D_MCT_M24 (0x02) /*!< MPEG-2, 4 AAC */ +#define ESP_A2D_MCT_ATRAC (0x04) /*!< ATRAC family */ +#define ESP_A2D_MCT_NON_A2DP (0xff) + +typedef uint8_t esp_a2d_mct_t; + +/// A2DP media codec capabilities union +typedef struct { + esp_a2d_mct_t type; /*!< A2DP media codec type */ +#define ESP_A2D_CIE_LEN_SBC (4) +#define ESP_A2D_CIE_LEN_M12 (4) +#define ESP_A2D_CIE_LEN_M24 (6) +#define ESP_A2D_CIE_LEN_ATRAC (7) + union { + uint8_t sbc[ESP_A2D_CIE_LEN_SBC]; + uint8_t m12[ESP_A2D_CIE_LEN_M12]; + uint8_t m24[ESP_A2D_CIE_LEN_M24]; + uint8_t atrac[ESP_A2D_CIE_LEN_ATRAC]; + } cie; /*!< A2DP codec information element */ +} __attribute__((packed)) esp_a2d_mcc_t; + +/// Bluetooth A2DP connection states +typedef enum { + ESP_A2D_CONNECTION_STATE_DISCONNECTED = 0, /*!< connection released */ + ESP_A2D_CONNECTION_STATE_CONNECTING, /*!< connecting remote device */ + ESP_A2D_CONNECTION_STATE_CONNECTED, /*!< connection established */ + ESP_A2D_CONNECTION_STATE_DISCONNECTING /*!< disconnecting remote device */ +} esp_a2d_connection_state_t; + +/// Bluetooth A2DP disconnection reason +typedef enum { + ESP_A2D_DISC_RSN_NORMAL = 0, /*!< Finished disconnection that is initiated by local or remote device */ + ESP_A2D_DISC_RSN_ABNORMAL /*!< Abnormal disconnection caused by signal loss */ +} esp_a2d_disc_rsn_t; + +/// Bluetooth A2DP datapath states +typedef enum { + ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND = 0, /*!< audio stream datapath suspended by remote device */ + ESP_A2D_AUDIO_STATE_STOPPED, /*!< audio stream datapath stopped */ + ESP_A2D_AUDIO_STATE_STARTED, /*!< audio stream datapath started */ +} esp_a2d_audio_state_t; + +/// A2DP callback events +typedef enum { + ESP_A2D_CONNECTION_STATE_EVT = 0, /*!< connection state changed event */ + ESP_A2D_AUDIO_STATE_EVT = 1, /*!< audio stream transmission state changed event */ + ESP_A2D_AUDIO_CFG_EVT = 2 /*!< audio codec is configured */ +} esp_a2d_cb_event_t; + +/// A2DP state callback parameters +typedef union { + /** + * @brief ESP_A2D_CONNECTION_STATE_EVT + */ + struct a2d_conn_stat_param { + esp_a2d_connection_state_t state; /*!< one of values from esp_a2d_connection_state_t */ + esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */ + esp_a2d_disc_rsn_t disc_rsn; /*!< reason of disconnection for "DISCONNECTED" */ + } conn_stat; /*!< A2DP connection status */ + + /** + * @brief ESP_A2D_AUDIO_STATE_EVT + */ + struct a2d_audio_stat_param { + esp_a2d_audio_state_t state; /*!< one of the values from esp_a2d_audio_state_t */ + esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */ + } audio_stat; /*!< audio stream playing state */ + + /** + * @brief ESP_A2D_AUDIO_CFG_EVT + */ + struct a2d_audio_cfg_param { + esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */ + esp_a2d_mcc_t mcc; /*!< A2DP media codec capability information */ + } audio_cfg; /*!< media codec configuration infomation */ +} esp_a2d_cb_param_t; + +/** + * @brief A2DP profile callback function type + * @param event : Event type + * @param param : Pointer to callback parameter + */ +typedef void (* esp_a2d_cb_t)(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param); + +/** + * @brief A2DP profile data callback function + * + * @param[in] buf : data received from A2DP source device and is PCM format decoder from SBC decoder; + * buf references to a static memory block and can be overwritten by upcoming data + * + * @param[in] len : size(in bytes) in buf + * + */ +typedef void (* esp_a2d_data_cb_t)(const uint8_t *buf, uint32_t len); + + +/** + * @brief Register application callback function to A2DP module. This function should be called + * only after esp_bluedroid_enable() completes successfully + * + * @param[in] callback: A2DP sink event callback function + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: if callback is a NULL function pointer + * + */ +esp_err_t esp_a2d_register_callback(esp_a2d_cb_t callback); + + +/** + * @brief Register A2DP sink data output function; For now the output is PCM data stream decoded + * from SBC format. This function should be called only after esp_bluedroid_enable() + * completes successfully + * + * @param[in] callback: A2DP data callback function + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: if callback is a NULL function pointer + * + */ +esp_err_t esp_a2d_register_data_callback(esp_a2d_data_cb_t callback); + + +/** + * + * @brief Initialize the bluetooth A2DP sink module. This function should be called + * after esp_bluedroid_enable() completes successfully + * + * @return + * - ESP_OK: if the initialization request is sent successfully + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_a2d_sink_init(void); + + +/** + * + * @brief De-initialize for A2DP sink module. This function + * should be called only after esp_bluedroid_enable() completes successfully + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_a2d_sink_deinit(void); + + +/** + * + * @brief Connect the remote bluetooth device bluetooth, must after esp_a2d_sink_init() + * + * @param[in] remote_bda: remote bluetooth device address + * + * @return + * - ESP_OK: connect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_a2d_sink_connect(esp_bd_addr_t remote_bda); + + +/** + * + * @brief Disconnect the remote bluetooth device + * + * @param[in] remote_bda: remote bluetooth device address + * @return + * - ESP_OK: disconnect request is sent to lower layer + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_a2d_sink_disconnect(esp_bd_addr_t remote_bda); + +#ifdef __cplusplus +} +#endif + + +#endif /* __ESP_A2DP_API_H__ */ diff --git a/components/bt/bluedroid/api/include/esp_avrc_api.h b/components/bt/bluedroid/api/include/esp_avrc_api.h new file mode 100644 index 0000000000..719a19f19c --- /dev/null +++ b/components/bt/bluedroid/api/include/esp_avrc_api.h @@ -0,0 +1,153 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __ESP_AVRC_API_H__ +#define __ESP_AVRC_API_H__ + +#include +#include +#include "esp_err.h" +#include "esp_bt_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// AVRC feature bit mask +typedef enum { + ESP_AVRC_FEAT_RCTG = 0x0001, /*!< remote control target */ + ESP_AVRC_FEAT_RCCT = 0x0002, /*!< remote control controller */ + ESP_AVRC_FEAT_VENDOR = 0x0008, /*!< remote control vendor dependent commands */ + ESP_AVRC_FEAT_BROWSE = 0x0010, /*!< use browsing channel */ + ESP_AVRC_FEAT_META_DATA = 0x0040, /*!< remote control metadata transfer command/response */ + ESP_AVRC_FEAT_ADV_CTRL = 0x0200, /*!< remote control advanced control commmand/response */ +} esp_avrc_features_t; + +/// AVRC passthrough command code +typedef enum { + ESP_AVRC_PT_CMD_PLAY = 0x44, /*!< play */ + ESP_AVRC_PT_CMD_STOP = 0x45, /*!< stop */ + ESP_AVRC_PT_CMD_PAUSE = 0x46, /*!< pause */ + ESP_AVRC_PT_CMD_FORWARD = 0x4B, /*!< forward */ + ESP_AVRC_PT_CMD_BACKWARD = 0x4C /*!< backward */ +} esp_avrc_pt_cmd_t; + +/// AVRC passthrough command state +typedef enum { + ESP_AVRC_PT_CMD_STATE_PRESSED = 0, /*!< key pressed */ + ESP_AVRC_PT_CMD_STATE_RELEASED = 1 /*!< key released */ +} esp_avrc_pt_cmd_state_t; + +/// AVRC Controller callback events +typedef enum { + ESP_AVRC_CT_CONNECTION_STATE_EVT = 0, /*!< connection state changed event */ + ESP_AVRC_CT_PASSTHROUGH_RSP_EVT = 1, /*!< passthrough response event */ + ESP_AVRC_CT_MAX_EVT +} esp_avrc_ct_cb_event_t; + +/// AVRC controller callback parameters +typedef union { + /** + * @brief ESP_AVRC_CT_CONNECTION_STATE_EVT + */ + struct avrc_ct_conn_stat_param { + bool connected; /*!< whether AVRC connection is set up */ + uint32_t feat_mask; /*!< AVRC feature mask of remote device */ + esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */ + } conn_stat; /*!< AVRC connection status */ + + /** + * @brief ESP_AVRC_CT_PASSTHROUGH_RSP_EVT + */ + struct avrc_ct_psth_rsp_param { + uint8_t tl; /*!< transaction label, 0 to 15 */ + uint8_t key_code; /*!< passthrough command code */ + uint8_t key_state; /*!< 0 for PRESSED, 1 for RELEASED */ + } psth_rsp; /*!< passthrough command response */ +} esp_avrc_ct_cb_param_t; + + +/** + * @brief AVRCP controller callback function type + * @param event : Event type + * @param param : Pointer to callback parameter union + */ +typedef void (* esp_avrc_ct_cb_t)(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param); + + +/** + * @brief Register application callbacks to AVRCP module; for now only AVRCP Controller + * role is supported. This function should be called after esp_bluedroid_enable() + * completes successfully + * + * @param[in] callback: AVRCP controller callback function + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_avrc_ct_register_callback(esp_avrc_ct_cb_t callback); + + +/** + * + * @brief Initialize the bluetooth AVRCP controller module, This function should be called + * after esp_bluedroid_enable() completes successfully + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + * + */ +esp_err_t esp_avrc_ct_init(void); + + +/** + * + * @brief De-initialize AVRCP controller module. This function should be called after + * after esp_bluedroid_enable() completes successfully + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + */ +esp_err_t esp_avrc_ct_deinit(void); + + +/** + * @brief Send passthrough command to AVRCP target, This function should be called after + * ESP_AVRC_CT_CONNECTION_STATE_EVT is received and AVRCP connection is established + * + * @param[in] tl : transaction label, 0 to 15, consecutive commands should use different values. + * @param[in] key_code : passthrough command code, e.g. ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STOP, etc. + * @param[in] key_state : passthrough command key state, ESP_AVRC_PT_CMD_STATE_PRESSED or + * ESP_AVRC_PT_CMD_STATE_PRESSED + * + * @return + * - ESP_OK: success + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + */ +esp_err_t esp_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state); + + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_AVRC_API_H__ */ diff --git a/components/bt/bluedroid/api/include/esp_bt_device.h b/components/bt/bluedroid/api/include/esp_bt_device.h index c84d042d66..d3c3f79c55 100644 --- a/components/bt/bluedroid/api/include/esp_bt_device.h +++ b/components/bt/bluedroid/api/include/esp_bt_device.h @@ -17,6 +17,8 @@ #include #include +#include "esp_err.h" +#include "esp_bt_defs.h" #ifdef __cplusplus extern "C" { @@ -30,6 +32,21 @@ extern "C" { */ const uint8_t *esp_bt_dev_get_address(void); + +/** + * @brief Set bluetooth device name. This function should be called after esp_bluedroid_enable() + * completes successfully + * + * @param[in] name : device name to be set + * + * @return + * - ESP_OK : Succeed + * - ESP_ERR_INVALID_ARG : if name is NULL pointer or empty, or string length out of limit + * - ESP_INVALID_STATE : if bluetooth stack is not yet enabled + * - ESP_FAIL : others + */ +esp_err_t esp_bt_dev_set_device_name(const char *name); + #ifdef __cplusplus } #endif diff --git a/components/bt/bluedroid/api/include/esp_gap_bt_api.h b/components/bt/bluedroid/api/include/esp_gap_bt_api.h new file mode 100644 index 0000000000..5efdd63326 --- /dev/null +++ b/components/bt/bluedroid/api/include/esp_gap_bt_api.h @@ -0,0 +1,52 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __ESP_GAP_BT_API_H__ +#define __ESP_GAP_BT_API_H__ + +#include +#include "esp_err.h" +#include "esp_bt_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/// Discoverability and Connectability mode +typedef enum { + ESP_BT_SCAN_MODE_NONE = 0, /*!< Neither discoverable nor connectable */ + ESP_BT_SCAN_MODE_CONNECTABLE, /*!< Connectable but not discoverable */ + ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE /*!< both discoverable and connectaable */ +} esp_bt_scan_mode_t; + +/** + * @brief Set discoverability and connectability mode for legacy bluetooth. This function should + * be called after esp_bluedroid_enable() completes successfully + * + * @param[in] mode : one of the enums of bt_scan_mode_t + * + * @return + * - ESP_OK : Succeed + * - ESP_ERR_INVALID_ARG: if argument invalid + * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled + * - ESP_FAIL: others + */ +esp_err_t esp_bt_gap_set_scan_mode(esp_bt_scan_mode_t mode); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_GAP_BT_API_H__ */ diff --git a/components/bt/bluedroid/bta/ar/bta_ar.c b/components/bt/bluedroid/bta/ar/bta_ar.c new file mode 100644 index 0000000000..9c672329e3 --- /dev/null +++ b/components/bt/bluedroid/bta/ar/bta_ar.c @@ -0,0 +1,316 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the implementation for the audio/video registration module. + * + ******************************************************************************/ + +#include "bt_target.h" +#include +#include "bta_ar_api.h" +#include "bta_ar_int.h" + +#if BTA_AR_INCLUDED + +/* AV control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_AR_CB bta_ar_cb; +#endif + +/******************************************************************************* +** +** Function bta_ar_id +** +** Description This function maps sys_id to ar id mask. +** +** Returns void +** +*******************************************************************************/ +static UINT8 bta_ar_id(tBTA_SYS_ID sys_id) +{ + UINT8 mask = 0; + if (sys_id == BTA_ID_AV) { + mask = BTA_AR_AV_MASK; + } else if (sys_id == BTA_ID_AVK) { + mask = BTA_AR_AVK_MASK; + } + + return mask; +} + +/******************************************************************************* +** +** Function bta_ar_init +** +** Description This function is called to register to AVDTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_init(void) +{ + /* initialize control block */ + memset(&bta_ar_cb, 0, sizeof(tBTA_AR_CB)); +} + +/******************************************************************************* +** +** Function bta_ar_reg_avdt +** +** Description This function is called to register to AVDTP. +** +** Returns void +** +*******************************************************************************/ +static void bta_ar_avdt_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + /* route the AVDT registration callback to av or avk */ + if (bta_ar_cb.p_av_conn_cback) { + (*bta_ar_cb.p_av_conn_cback)(handle, bd_addr, event, p_data); + } + if (bta_ar_cb.p_avk_conn_cback) { + (*bta_ar_cb.p_avk_conn_cback)(handle, bd_addr, event, p_data); + } +} + +/******************************************************************************* +** +** Function bta_ar_reg_avdt +** +** Description AR module registration to AVDT. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_reg_avdt(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback, tBTA_SYS_ID sys_id) +{ + UINT8 mask = 0; + + if (sys_id == BTA_ID_AV) { + bta_ar_cb.p_av_conn_cback = p_cback; + mask = BTA_AR_AV_MASK; + } else if (sys_id == BTA_ID_AVK) { + bta_ar_cb.p_avk_conn_cback = p_cback; + mask = BTA_AR_AVK_MASK; + } +#if (BTA_AR_DEBUG == TRUE) + else { + APPL_TRACE_ERROR("bta_ar_reg_avdt: the registration is from wrong sys_id:%d", sys_id); + } +#endif + + if (mask) { + if (bta_ar_cb.avdt_registered == 0) { + AVDT_Register(p_reg, bta_ar_avdt_cback); + } + bta_ar_cb.avdt_registered |= mask; + } +} + +/******************************************************************************* +** +** Function bta_ar_dereg_avdt +** +** Description This function is called to de-register from AVDTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id) +{ + UINT8 mask = 0; + + if (sys_id == BTA_ID_AV) { + bta_ar_cb.p_av_conn_cback = NULL; + mask = BTA_AR_AV_MASK; + } else if (sys_id == BTA_ID_AVK) { + bta_ar_cb.p_avk_conn_cback = NULL; + mask = BTA_AR_AVK_MASK; + } + bta_ar_cb.avdt_registered &= ~mask; + + if (bta_ar_cb.avdt_registered == 0) { + AVDT_Deregister(); + } +} + +/******************************************************************************* +** +** Function bta_ar_avdt_conn +** +** Description This function is called to let ar know that some AVDTP profile +** is connected for this sys_id. +** If the other sys modules started a timer for PENDING_EVT, +** the timer can be stopped now. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr) +{ + UINT8 event = BTA_AR_AVDT_CONN_EVT; + tAVDT_CTRL data; + + if (sys_id == BTA_ID_AV) { + if (bta_ar_cb.p_avk_conn_cback) { + (*bta_ar_cb.p_avk_conn_cback)(0, bd_addr, event, &data); + } + } else if (sys_id == BTA_ID_AVK) { + if (bta_ar_cb.p_av_conn_cback) { + (*bta_ar_cb.p_av_conn_cback)(0, bd_addr, event, &data); + } + } +} + +/******************************************************************************* +** +** Function bta_ar_reg_avct +** +** Description This function is called to register to AVCTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_reg_avct(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask, tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + + if (mask) { + if (bta_ar_cb.avct_registered == 0) { + AVCT_Register(mtu, mtu_br, sec_mask); + } + bta_ar_cb.avct_registered |= mask; + } +} + +/******************************************************************************* +** +** Function bta_ar_dereg_avct +** +** Description This function is called to deregister from AVCTP. +** +** Returns void +** +*******************************************************************************/ +void bta_ar_dereg_avct(tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + + bta_ar_cb.avct_registered &= ~mask; + + if (bta_ar_cb.avct_registered == 0) { + AVCT_Deregister(); + } +} + +/****************************************************************************** +** +** Function bta_ar_reg_avrc +** +** Description This function is called to register an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +void bta_ar_reg_avrc(UINT16 service_uuid, char *service_name, char *provider_name, + UINT16 categories, tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + UINT8 temp[8], *p; + + if (!mask || !categories) { + return; + } + + if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) { + if (bta_ar_cb.sdp_tg_handle == 0) { + bta_ar_cb.tg_registered = mask; + bta_ar_cb.sdp_tg_handle = SDP_CreateRecord(); + AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_tg_handle); + bta_sys_add_uuid(service_uuid); + } + /* only one TG is allowed (first-come, first-served). + * If sdp_tg_handle is non-0, ignore this request */ + } else if ((service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) || (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_CONTROL)) { + bta_ar_cb.ct_categories [mask - 1] = categories; + categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1]; + if (bta_ar_cb.sdp_ct_handle == 0) { + bta_ar_cb.sdp_ct_handle = SDP_CreateRecord(); + AVRC_AddRecord(service_uuid, service_name, provider_name, categories, bta_ar_cb.sdp_ct_handle); + bta_sys_add_uuid(service_uuid); + } else { + /* multiple CTs are allowed. + * Change supported categories on the second one */ + p = temp; + UINT16_TO_BE_STREAM(p, categories); + SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (UINT32)2, (UINT8 *)temp); + } + } +} + +/****************************************************************************** +** +** Function bta_ar_dereg_avrc +** +** Description This function is called to de-register/delete an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +void bta_ar_dereg_avrc(UINT16 service_uuid, tBTA_SYS_ID sys_id) +{ + UINT8 mask = bta_ar_id (sys_id); + UINT16 categories = 0; + UINT8 temp[8], *p; + + if (!mask) { + return; + } + + if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET) { + if (bta_ar_cb.sdp_tg_handle && mask == bta_ar_cb.tg_registered) { + bta_ar_cb.tg_registered = 0; + SDP_DeleteRecord(bta_ar_cb.sdp_tg_handle); + bta_ar_cb.sdp_tg_handle = 0; + bta_sys_remove_uuid(service_uuid); + } + } else if (service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL) { + if (bta_ar_cb.sdp_ct_handle) { + bta_ar_cb.ct_categories [mask - 1] = 0; + categories = bta_ar_cb.ct_categories[0] | bta_ar_cb.ct_categories[1]; + if (!categories) { + /* no CT is still registered - cleaup */ + SDP_DeleteRecord(bta_ar_cb.sdp_ct_handle); + bta_ar_cb.sdp_ct_handle = 0; + bta_sys_remove_uuid(service_uuid); + } else { + /* change supported categories to the remaning one */ + p = temp; + UINT16_TO_BE_STREAM(p, categories); + SDP_AddAttribute(bta_ar_cb.sdp_ct_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (UINT32)2, (UINT8 *)temp); + } + } + } + +} + +#endif /* #if BTA_AR_INCLUDED */ diff --git a/components/bt/bluedroid/bta/ar/bta_ar_int.h b/components/bt/bluedroid/bta/ar/bta_ar_int.h new file mode 100644 index 0000000000..4bbf20401b --- /dev/null +++ b/components/bt/bluedroid/bta/ar/bta_ar_int.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Copyright (C) 2008-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the private interface file for the BTA audio/video registration + * module. + * + ******************************************************************************/ +#ifndef BTA_AR_INT_H +#define BTA_AR_INT_H + +#include "bta_av_api.h" + + +#ifndef BTA_AR_DEBUG +#define BTA_AR_DEBUG FALSE +#endif + +#define BTA_AR_AV_MASK 0x01 +#define BTA_AR_AVK_MASK 0x02 + +/* data associated with BTA_AR */ +typedef struct { + tAVDT_CTRL_CBACK *p_av_conn_cback; /* av connection callback function */ + tAVDT_CTRL_CBACK *p_avk_conn_cback; /* avk connection callback function */ + UINT8 avdt_registered; + UINT8 avct_registered; + UINT32 sdp_tg_handle; + UINT32 sdp_ct_handle; + UINT16 ct_categories[2]; + UINT8 tg_registered; + tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */ +} tBTA_AR_CB; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* control block declaration */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_AR_CB bta_ar_cb; +#else +extern tBTA_AR_CB *bta_ar_cb_ptr; +#define bta_ar_cb (*bta_ar_cb_ptr) +#endif + +#endif /* BTA_AR_INT_H */ diff --git a/components/bt/bluedroid/bta/av/bta_av_aact.c b/components/bt/bluedroid/bta/av/bta_av_aact.c new file mode 100644 index 0000000000..91def0985b --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_aact.c @@ -0,0 +1,2919 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains action functions for advanced audio/video stream + * state machine. these functions are shared by both audio and video + * streams. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +// #include +#include "bt_trace.h" +#include + +// #include + +#include "bta_av_int.h" +#include "avdt_api.h" +#include "utl.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif + +/***************************************************************************** +** Constants +*****************************************************************************/ + +/* the delay time in milliseconds to start service discovery on AVRCP */ +#ifndef BTA_AV_RC_DISC_TIME_VAL +#define BTA_AV_RC_DISC_TIME_VAL 3500 +#endif + +/* the timer in milliseconds to guard against link busy and AVDT_CloseReq failed to be sent */ +#ifndef BTA_AV_CLOSE_REQ_TIME_VAL +#define BTA_AV_CLOSE_REQ_TIME_VAL 4000 +#endif + +/* number to retry on reconfigure failure - some headsets requirs this number to be more than 1 */ +#ifndef BTA_AV_RECONFIG_RETRY +#define BTA_AV_RECONFIG_RETRY 6 +#endif + +static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); + +/* state machine states */ +enum { + BTA_AV_INIT_SST, + BTA_AV_INCOMING_SST, + BTA_AV_OPENING_SST, + BTA_AV_OPEN_SST, + BTA_AV_RCFG_SST, + BTA_AV_CLOSING_SST +}; + + +/* the call out functions for audio stream */ +/* const tBTA_AV_CO_FUNCTS bta_av_a2d_cos = +{ + bta_av_co_audio_init, + bta_av_co_audio_disc_res, + bta_av_co_audio_getconfig, + bta_av_co_audio_setconfig, + bta_av_co_audio_open, + bta_av_co_audio_close, + bta_av_co_audio_start, + bta_av_co_audio_stop, + bta_av_co_audio_src_data_path, + bta_av_co_audio_delay +}; +*/ +tBTA_AV_CO_FUNCTS *p_bta_av_a2d_cos = NULL; + + + +/* ssm action functions for audio stream */ +const tBTA_AV_SACT bta_av_a2d_action[] = { + bta_av_do_disc_a2d, /* BTA_AV_DO_DISC */ + bta_av_cleanup, /* BTA_AV_CLEANUP */ + bta_av_free_sdb, /* BTA_AV_FREE_SDB */ + bta_av_config_ind, /* BTA_AV_CONFIG_IND */ + bta_av_disconnect_req, /* BTA_AV_DISCONNECT_REQ */ + bta_av_security_req, /* BTA_AV_SECURITY_REQ */ + bta_av_security_rsp, /* BTA_AV_SECURITY_RSP */ + bta_av_setconfig_rsp, /* BTA_AV_SETCONFIG_RSP */ + bta_av_st_rc_timer, /* BTA_AV_ST_RC_TIMER */ + bta_av_str_opened, /* BTA_AV_STR_OPENED */ + bta_av_security_ind, /* BTA_AV_SECURITY_IND */ + bta_av_security_cfm, /* BTA_AV_SECURITY_CFM */ + bta_av_do_close, /* BTA_AV_DO_CLOSE */ + bta_av_connect_req, /* BTA_AV_CONNECT_REQ */ + bta_av_sdp_failed, /* BTA_AV_SDP_FAILED */ + bta_av_disc_results, /* BTA_AV_DISC_RESULTS */ + bta_av_disc_res_as_acp, /* BTA_AV_DISC_RES_AS_ACP */ + bta_av_open_failed, /* BTA_AV_OPEN_FAILED */ + bta_av_getcap_results, /* BTA_AV_GETCAP_RESULTS */ + bta_av_setconfig_rej, /* BTA_AV_SETCONFIG_REJ */ + bta_av_discover_req, /* BTA_AV_DISCOVER_REQ */ + bta_av_conn_failed, /* BTA_AV_CONN_FAILED */ + bta_av_do_start, /* BTA_AV_DO_START */ + bta_av_str_stopped, /* BTA_AV_STR_STOPPED */ + bta_av_reconfig, /* BTA_AV_RECONFIG */ + bta_av_data_path, /* BTA_AV_DATA_PATH */ + bta_av_start_ok, /* BTA_AV_START_OK */ + bta_av_start_failed, /* BTA_AV_START_FAILED */ + bta_av_str_closed, /* BTA_AV_STR_CLOSED */ + bta_av_clr_cong, /* BTA_AV_CLR_CONG */ + bta_av_suspend_cfm, /* BTA_AV_SUSPEND_CFM */ + bta_av_rcfg_str_ok, /* BTA_AV_RCFG_STR_OK */ + bta_av_rcfg_failed, /* BTA_AV_RCFG_FAILED */ + bta_av_rcfg_connect, /* BTA_AV_RCFG_CONNECT */ + bta_av_rcfg_discntd, /* BTA_AV_RCFG_DISCNTD */ + bta_av_suspend_cont, /* BTA_AV_SUSPEND_CONT */ + bta_av_rcfg_cfm, /* BTA_AV_RCFG_CFM */ + bta_av_rcfg_open, /* BTA_AV_RCFG_OPEN */ + bta_av_security_rej, /* BTA_AV_SECURITY_REJ */ + bta_av_open_rc, /* BTA_AV_OPEN_RC */ + bta_av_chk_2nd_start, /* BTA_AV_CHK_2ND_START */ + bta_av_save_caps, /* BTA_AV_SAVE_CAPS */ + bta_av_set_use_rc, /* BTA_AV_SET_USE_RC */ + bta_av_cco_close, /* BTA_AV_CCO_CLOSE */ + bta_av_switch_role, /* BTA_AV_SWITCH_ROLE */ + bta_av_role_res, /* BTA_AV_ROLE_RES */ + bta_av_delay_co, /* BTA_AV_DELAY_CO */ + bta_av_open_at_inc, /* BTA_AV_OPEN_AT_INC */ + NULL +}; + +/* these tables translate AVDT events to SSM events */ +static const UINT16 bta_av_stream_evt_ok[] = { + BTA_AV_STR_DISC_OK_EVT, /* AVDT_DISCOVER_CFM_EVT */ + BTA_AV_STR_GETCAP_OK_EVT, /* AVDT_GETCAP_CFM_EVT */ + BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_CFM_EVT */ + BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */ + BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */ + BTA_AV_STR_START_OK_EVT, /* AVDT_START_CFM_EVT */ + BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */ + BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */ + 0, /* AVDT_RECONFIG_IND_EVT */ + BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */ + BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */ + BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */ + BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */ + BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */ +#if (AVDT_REPORTING == TRUE) + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */ + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */ +#endif + BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */ + 0 /* AVDT_DELAY_REPORT_CFM_EVT */ +}; + +static const UINT16 bta_av_stream_evt_fail[] = { + BTA_AV_STR_DISC_FAIL_EVT, /* AVDT_DISCOVER_CFM_EVT */ + BTA_AV_STR_GETCAP_FAIL_EVT, /* AVDT_GETCAP_CFM_EVT */ + BTA_AV_STR_OPEN_FAIL_EVT, /* AVDT_OPEN_CFM_EVT */ + BTA_AV_STR_OPEN_OK_EVT, /* AVDT_OPEN_IND_EVT */ + BTA_AV_STR_CONFIG_IND_EVT, /* AVDT_CONFIG_IND_EVT */ + BTA_AV_STR_START_FAIL_EVT, /* AVDT_START_CFM_EVT */ + BTA_AV_STR_START_OK_EVT, /* AVDT_START_IND_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_CFM_EVT */ + BTA_AV_STR_SUSPEND_CFM_EVT, /* AVDT_SUSPEND_IND_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_CFM_EVT */ + BTA_AV_STR_CLOSE_EVT, /* AVDT_CLOSE_IND_EVT */ + BTA_AV_STR_RECONFIG_CFM_EVT, /* AVDT_RECONFIG_CFM_EVT */ + 0, /* AVDT_RECONFIG_IND_EVT */ + BTA_AV_STR_SECURITY_CFM_EVT, /* AVDT_SECURITY_CFM_EVT */ + BTA_AV_STR_SECURITY_IND_EVT, /* AVDT_SECURITY_IND_EVT */ + BTA_AV_STR_WRITE_CFM_EVT, /* AVDT_WRITE_CFM_EVT */ + BTA_AV_AVDT_CONNECT_EVT, /* AVDT_CONNECT_IND_EVT */ + BTA_AV_AVDT_DISCONNECT_EVT, /* AVDT_DISCONNECT_IND_EVT */ +#if (AVDT_REPORTING == TRUE) + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_CONN_EVT */ + BTA_AV_AVDT_RPT_CONN_EVT, /* AVDT_REPORT_DISCONN_EVT */ +#endif + BTA_AV_AVDT_DELAY_RPT_EVT, /* AVDT_DELAY_REPORT_EVT */ + 0 /* AVDT_DELAY_REPORT_CFM_EVT */ +}; + +void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt); +static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#if BTA_AV_NUM_STRS > 2 +static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +#if BTA_AV_NUM_STRS > 3 +static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +#if BTA_AV_NUM_STRS > 4 +static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +#if BTA_AV_NUM_STRS > 5 +static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +#endif +/* the array of callback functions to receive events from AVDT control channel */ +tAVDT_CTRL_CBACK *const bta_av_dt_cback[] = { + bta_av_stream0_cback + , bta_av_stream1_cback +#if BTA_AV_NUM_STRS > 2 + , bta_av_stream2_cback +#endif +#if BTA_AV_NUM_STRS > 3 + , bta_av_stream3_cback +#endif +#if BTA_AV_NUM_STRS > 4 + , bta_av_stream4_cback +#endif +#if BTA_AV_NUM_STRS > 5 + , bta_av_stream5_cback +#endif +}; +/*********************************************** +** +** Function bta_get_scb_handle +** +** Description gives the registered AVDT handle.by checking with sep_type. +** +** +** Returns void +***********************************************/ +static UINT8 bta_av_get_scb_handle(tBTA_AV_SCB *p_scb, UINT8 local_sep) +{ + UINT8 xx = 0; + for (xx = 0; xx < BTA_AV_MAX_SEPS; xx++) { + if ((p_scb->seps[xx].tsep == local_sep) && + (p_scb->seps[xx].codec_type == p_scb->codec_type)) { + return (p_scb->seps[xx].av_handle); + } + } + APPL_TRACE_DEBUG(" bta_av_get_scb_handle appropiate sep_type not found") + return 0; /* return invalid handle */ +} + +/*********************************************** +** +** Function bta_av_get_scb_sep_type +** +** Description gives the sep type by cross-checking with AVDT handle +** +** +** Returns void +***********************************************/ +static UINT8 bta_av_get_scb_sep_type(tBTA_AV_SCB *p_scb, UINT8 tavdt_handle) +{ + UINT8 xx = 0; + for (xx = 0; xx < BTA_AV_MAX_SEPS; xx++) { + if (p_scb->seps[xx].av_handle == tavdt_handle) { + return (p_scb->seps[xx].tsep); + } + } + APPL_TRACE_DEBUG(" bta_av_get_scb_sep_type appropiate handle not found") + return 3; /* return invalid sep type */ +} + +/******************************************************************************* +** +** Function bta_av_save_addr +** +** Description copy the bd_addr and maybe reset the supported flags +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_save_addr(tBTA_AV_SCB *p_scb, const BD_ADDR b) +{ + APPL_TRACE_DEBUG("bta_av_save_addr r:%d, s:%d", + p_scb->recfg_sup, p_scb->suspend_sup); + if (bdcmp(p_scb->peer_addr, b) != 0) { + APPL_TRACE_ERROR("reset flags"); + /* a new addr, reset the supported flags */ + p_scb->recfg_sup = TRUE; + p_scb->suspend_sup = TRUE; + } + + /* do this copy anyway, just in case the first addr matches + * the control block one by accident */ + bdcpy(p_scb->peer_addr, b); +} + +/******************************************************************************* +** +** Function notify_start_failed +** +** Description notify up-layer AV start failed +** +** +** Returns void +** +*******************************************************************************/ +static void notify_start_failed(tBTA_AV_SCB *p_scb) +{ + tBTA_AV_START start; + /* if start failed, clear role */ + p_scb->role &= ~BTA_AV_ROLE_START_INT; + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL; + start.initiator = TRUE; + start.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); +} + +/******************************************************************************* +** +** Function bta_av_st_rc_timer +** +** Description start the AVRC timer if no RC connection & CT is supported & +** RC is used or +** as ACP (we do not really know if we want AVRC) +** +** Returns void +** +*******************************************************************************/ +static void bta_av_st_rc_timer(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_st_rc_timer rc_handle:%d, use_rc: %d", + p_scb->rc_handle, p_scb->use_rc); + /* for outgoing RC connection as INT/CT */ + if ( (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) && + /*(bta_av_cb.features & BTA_AV_FEAT_RCCT) &&*/ + (p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP)) ) { + if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) { + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL); + } else { + p_scb->wait |= BTA_AV_WAIT_CHECK_RC; + } + } + +} + +/******************************************************************************* +** +** Function bta_av_next_getcap +** +** Description The function gets the capabilities of the next available +** stream found in the discovery results. +** +** Returns TRUE if we sent request to AVDT, FALSE otherwise. +** +*******************************************************************************/ +static BOOLEAN bta_av_next_getcap(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + int i; + tAVDT_GETCAP_REQ *p_req; + BOOLEAN sent_cmd = FALSE; + UINT16 uuid_int = p_scb->uuid_int; + UINT8 sep_requested = 0; + + if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) { + sep_requested = AVDT_TSEP_SNK; + } else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK) { + sep_requested = AVDT_TSEP_SRC; + } + + for (i = p_scb->sep_info_idx; i < p_scb->num_seps; i++) { + /* steam not in use, is a sink, and is the right media type (audio/video) */ + if ((p_scb->sep_info[i].in_use == FALSE) && + (p_scb->sep_info[i].tsep == sep_requested) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) { + p_scb->sep_info_idx = i; + + /* we got a stream; get its capabilities */ + if (p_scb->p_cap == NULL) { + p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG)); + } + if (p_scb->p_cap == NULL) { + i = p_scb->num_seps; + break; + } + if (p_scb->avdt_version >= AVDT_VERSION_SYNC) { + p_req = AVDT_GetAllCapReq; + } else { + p_req = AVDT_GetCapReq; + } + (*p_req)(p_scb->peer_addr, + p_scb->sep_info[i].seid, + p_scb->p_cap, bta_av_dt_cback[p_scb->hdi]); + sent_cmd = TRUE; + break; + } + } + + /* if no streams available then stream open fails */ + if (!sent_cmd) { + bta_av_ssm_execute(p_scb, BTA_AV_STR_GETCAP_FAIL_EVT, p_data); + } + + return sent_cmd; + +} + +/******************************************************************************* +** +** Function bta_av_proc_stream_evt +** +** Description Utility function to compose stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_proc_stream_evt(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data, int index) +{ + tBTA_AV_STR_MSG *p_msg; + UINT16 sec_len = 0; + tBTA_AV_SCB *p_scb = bta_av_cb.p_scb[index]; + int xx; + + if (p_data) { + if (event == AVDT_SECURITY_IND_EVT) { + sec_len = (p_data->security_ind.len < BTA_AV_SECURITY_MAX_LEN) ? + p_data->security_ind.len : BTA_AV_SECURITY_MAX_LEN; + } else if (event == AVDT_SECURITY_CFM_EVT && p_data->hdr.err_code == 0) { + sec_len = (p_data->security_cfm.len < BTA_AV_SECURITY_MAX_LEN) ? + p_data->security_cfm.len : BTA_AV_SECURITY_MAX_LEN; + } + } + + if (p_scb && (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG) + sec_len))) != NULL) { + + /* copy event data, bd addr, and handle to event message buffer */ + p_msg->hdr.offset = 0; + + if (bd_addr != NULL) { + bdcpy(p_msg->bd_addr, bd_addr); + APPL_TRACE_DEBUG(" bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + bd_addr[0], bd_addr[1], + bd_addr[2], bd_addr[3], + bd_addr[4], bd_addr[5]); + } + + if (p_data != NULL) { + memcpy(&p_msg->msg, p_data, sizeof (tAVDT_CTRL)); + /* copy config params to event message buffer */ + switch (event) { + case AVDT_RECONFIG_CFM_EVT: + APPL_TRACE_DEBUG("reconfig cfm event codec info = 0x%06x-%06x-%06x-%02x", + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[0] << 16) + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[1] << 8) + p_msg->msg.reconfig_cfm.p_cfg->codec_info[2], + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[3] << 16) + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[4] << 8) + p_msg->msg.reconfig_cfm.p_cfg->codec_info[5], + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[6] << 16) + (p_msg->msg.reconfig_cfm.p_cfg->codec_info[7] << 8) + p_msg->msg.reconfig_cfm.p_cfg->codec_info[8], + p_msg->msg.reconfig_cfm.p_cfg->codec_info[9]); + break; + + + + case AVDT_CONFIG_IND_EVT: + /* We might have 2 SEP signallings(A2DP + VDP) with one peer device on one L2CAP. + * If we already have a signalling connection with the bd_addr and the streaming + * SST is at INIT state, change it to INCOMING state to handle the signalling + * from the 2nd SEP. */ + if ((bta_av_find_lcb(bd_addr, BTA_AV_LCB_FIND) != NULL) && (bta_av_is_scb_init(p_scb))) { + bta_av_set_scb_sst_incoming (p_scb); + + /* When ACP_CONNECT_EVT was received, we put first available scb to incoming state. + * Later when we receive AVDT_CONFIG_IND_EVT, we use a new p_scb and set its state to + * incoming which we do it above. + * We also have to set the old p_scb state to init to be used later */ + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + if ((bta_av_cb.p_scb[xx]) && (xx != index)) { + if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) { + bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST; + bta_av_cb.p_scb[xx]->coll_mask = 0; + break; + } + } + } + } + + memcpy(&p_msg->cfg, p_data->config_ind.p_cfg, sizeof(tAVDT_CFG)); + break; + + case AVDT_SECURITY_IND_EVT: + p_msg->msg.security_ind.p_data = (UINT8 *) (p_msg + 1); + memcpy(p_msg->msg.security_ind.p_data, p_data->security_ind.p_data, sec_len); + break; + + case AVDT_SECURITY_CFM_EVT: + p_msg->msg.security_cfm.p_data = (UINT8 *) (p_msg + 1); + if (p_data->hdr.err_code == 0) { + memcpy(p_msg->msg.security_cfm.p_data, p_data->security_cfm.p_data, sec_len); + } + break; + case AVDT_SUSPEND_IND_EVT: + p_msg->msg.hdr.err_code = 0; + break; + /* + case AVDT_CLOSE_CFM_EVT: + case AVDT_CLOSE_IND_EVT: + p_msg->disc_rsn = p_data->hdr.err_param; + break; + */ + default: + break; + } + } else { + p_msg->msg.hdr.err_code = 0; + } + + /* look up application event */ + if ((p_data == NULL) || (p_data->hdr.err_code == 0)) { + p_msg->hdr.event = bta_av_stream_evt_ok[event]; + } else { + p_msg->hdr.event = bta_av_stream_evt_fail[event]; + } + + p_msg->initiator = FALSE; + if (event == AVDT_SUSPEND_CFM_EVT) { + p_msg->initiator = TRUE; + } + + APPL_TRACE_VERBOSE("hndl:x%x", p_scb->hndl); + p_msg->hdr.layer_specific = p_scb->hndl; + p_msg->handle = handle; + p_msg->avdt_event = event; + bta_sys_sendmsg(p_msg); + } + + /* coverity[var_deref_model] */ + /* false-positive: bta_av_conn_cback only processes AVDT_CONNECT_IND_EVT and AVDT_DISCONNECT_IND_EVT event + * these 2 events always have associated p_data */ + if (p_data) { + bta_av_conn_cback(handle, bd_addr, event, p_data); + } else { + APPL_TRACE_ERROR("%s: p_data is null", __func__); + } +} + +/******************************************************************************* +** +** Function bta_av_stream_data_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) +{ + int index = 0; + tBTA_AV_SCB *p_scb ; + APPL_TRACE_DEBUG("bta_av_stream_data_cback avdt_handle: %d pkt_len=0x%x ofst = 0x%x", handle, p_pkt->len, p_pkt->offset); + APPL_TRACE_DEBUG(" Number of frames 0x%x", *((UINT8 *)(p_pkt + 1) + p_pkt->offset)); + APPL_TRACE_DEBUG("Sequence Number 0x%x", p_pkt->layer_specific); + /* Get SCB and correct sep type*/ + for (index = 0; index < BTA_AV_NUM_STRS; index ++ ) { + p_scb = bta_av_cb.p_scb[index]; + if ((p_scb->avdt_handle == handle) && (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) { + break; + } + } + if (index == BTA_AV_NUM_STRS) { /* cannot find correct handler */ + GKI_freebuf(p_pkt); + return; + } + p_pkt->event = BTA_AV_MEDIA_DATA_EVT; + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_DATA_EVT, (tBTA_AV_MEDIA *)p_pkt); + GKI_freebuf(p_pkt); /* a copy of packet had been delivered, we free this buffer */ +} + +/******************************************************************************* +** +** Function bta_av_stream0_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream0_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_VERBOSE("bta_av_stream0_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 0); +} + +/******************************************************************************* +** +** Function bta_av_stream1_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream1_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT("bta_av_stream1_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 1); +} + +#if BTA_AV_NUM_STRS > 2 +/******************************************************************************* +** +** Function bta_av_stream2_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream2_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT("bta_av_stream2_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 2); +} +#endif + +#if BTA_AV_NUM_STRS > 3 +/******************************************************************************* +** +** Function bta_av_stream3_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_stream3_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT("bta_av_stream3_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 3); +} +#endif + +/******************************************************************************* +** +** Function bta_av_stream4_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +#if BTA_AV_NUM_STRS > 4 +static void bta_av_stream4_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT("bta_av_stream4_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 4); +} +#endif + +/******************************************************************************* +** +** Function bta_av_stream5_cback +** +** Description This is the AVDTP callback function for stream events. +** +** Returns void +** +*******************************************************************************/ +#if BTA_AV_NUM_STRS > 5 +static void bta_av_stream5_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + APPL_TRACE_EVENT("bta_av_stream5_cback avdt_handle: %d event=0x%x", handle, event); + bta_av_proc_stream_evt(handle, bd_addr, event, p_data, 5); +} +#endif + +/******************************************************************************* +** +** Function bta_av_a2d_sdp_cback +** +** Description A2DP service discovery callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_a2d_sdp_cback(BOOLEAN found, tA2D_Service *p_service) +{ + tBTA_AV_SDP_RES *p_msg; + tBTA_AV_SCB *p_scb; + + if ((p_msg = (tBTA_AV_SDP_RES *) GKI_getbuf(sizeof(tBTA_AV_SDP_RES))) != NULL) { + p_msg->hdr.event = (found) ? BTA_AV_SDP_DISC_OK_EVT : BTA_AV_SDP_DISC_FAIL_EVT; + + p_scb = bta_av_hndl_to_scb(bta_av_cb.handle); + if (p_scb) { + if (found && (p_service != NULL)) { + p_scb->avdt_version = p_service->avdt_version; + } else { + p_scb->avdt_version = 0x00; + } + + p_msg->hdr.layer_specific = bta_av_cb.handle; + bta_sys_sendmsg(p_msg); + } else { + APPL_TRACE_ERROR ("bta_av_a2d_sdp_cback, no scb found for handle(0x%x)", bta_av_cb.handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_adjust_seps_idx +** +** Description adjust the sep_idx +** +** Returns +** +*******************************************************************************/ +static void bta_av_adjust_seps_idx(tBTA_AV_SCB *p_scb, UINT8 avdt_handle) +{ + int xx; + APPL_TRACE_DEBUG("bta_av_adjust_seps_idx codec_type: %d", p_scb->codec_type); + for (xx = 0; xx < BTA_AV_MAX_SEPS; xx++) { + APPL_TRACE_DEBUG("av_handle: %d codec_type: %d", + p_scb->seps[xx].av_handle, p_scb->seps[xx].codec_type); + if ((p_scb->seps[xx].av_handle && p_scb->codec_type == p_scb->seps[xx].codec_type) + && (p_scb->seps[xx].av_handle == avdt_handle)) { + p_scb->sep_idx = xx; + p_scb->avdt_handle = p_scb->seps[xx].av_handle; + break; + } + } +} + +/******************************************************************************* +** +** Function bta_av_switch_role +** +** Description Switch role was not started and a timer was started. +** another attempt to switch role now - still opening. +** +** Returns void +** +*******************************************************************************/ +void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RS_RES switch_res = BTA_AV_RS_NONE; + tBTA_AV_API_OPEN *p_buf = &p_scb->q_info.open; + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_switch_role wait:x%x", p_scb->wait); + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START) { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RETRY; + } + + /* clear the masks set when the timer is started */ + p_scb->wait &= ~(BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START); + + if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) { + if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT)) { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN; + } else { + /* this should not happen in theory. Just in case... + * continue to do_disc_a2d */ + switch_res = BTA_AV_RS_DONE; + } + } else { + /* report failure on OPEN */ + switch_res = BTA_AV_RS_FAIL; + } + + if (switch_res != BTA_AV_RS_NONE) { + if (bta_av_cb.rs_idx == (p_scb->hdi + 1)) { + bta_av_cb.rs_idx = 0; + } + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_RETRY; + p_scb->q_tag = 0; + p_buf->switch_res = switch_res; + bta_av_do_disc_a2d(p_scb, (tBTA_AV_DATA *)p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_role_res +** +** Description Handle the role changed event +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + BOOLEAN initiator = FALSE; + tBTA_AV_START start; + tBTA_AV_OPEN av_open; + + APPL_TRACE_DEBUG("bta_av_role_res q_tag:%d, wait:x%x, role:x%x", p_scb->q_tag, p_scb->wait, p_scb->role); + if (p_scb->role & BTA_AV_ROLE_START_INT) { + initiator = TRUE; + } + + if (p_scb->q_tag == BTA_AV_Q_TAG_START) { + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_STARTED) { + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + if (p_data->role_res.hci_status != HCI_SUCCESS) { + p_scb->role &= ~BTA_AV_ROLE_START_INT; + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + /* start failed because of role switch. */ + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL_ROLE; + start.hndl = p_scb->hndl; + start.initiator = initiator; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + } else { + bta_av_start_ok(p_scb, p_data); + } + } else if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_START) { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_FAILED; + } + } else if (p_scb->q_tag == BTA_AV_Q_TAG_OPEN) { + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_RES_OPEN) { + p_scb->role &= ~BTA_AV_ROLE_START_INT; + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + + if (p_data->role_res.hci_status != HCI_SUCCESS) { + /* Open failed because of role switch. */ + bdcpy(av_open.bd_addr, p_scb->peer_addr); + av_open.chnl = p_scb->chnl; + av_open.hndl = p_scb->hndl; + start.status = BTA_AV_FAIL_ROLE; + if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) { + av_open.sep = AVDT_TSEP_SNK; + } else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) { + av_open.sep = AVDT_TSEP_SRC; + } + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *)&av_open); + } else { + /* Continue av open process */ + p_scb->q_info.open.switch_res = BTA_AV_RS_DONE; + bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *) & (p_scb->q_info.open)); + } + } else { + APPL_TRACE_WARNING ("Unexpected role switch event: q_tag = %d wait = %d", p_scb->q_tag, p_scb->wait); + } + } + + APPL_TRACE_DEBUG("wait:x%x, role:x%x", p_scb->wait, p_scb->role); +} + +/******************************************************************************* +** +** Function bta_av_delay_co +** +** Description Call the delay call-out function to report the delay report +** from SNK +** +** Returns void +** +*******************************************************************************/ +void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + p_scb->p_cos->delay(p_scb->hndl, p_data->str_msg.msg.delay_rpt_cmd.delay); +} + +/******************************************************************************* +** +** Function bta_av_do_disc_a2d +** +** Description Do service discovery for A2DP. +** +** Returns void +** +*******************************************************************************/ +void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + BOOLEAN ok_continue = FALSE; + tA2D_SDP_DB_PARAMS db_params; + UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, + ATTR_ID_PROTOCOL_DESC_LIST, + ATTR_ID_BT_PROFILE_DESC_LIST + }; + UINT16 sdp_uuid = 0; /* UUID for which SDP has to be done */ + + APPL_TRACE_DEBUG("bta_av_do_disc_a2d use_rc: %d rs:%d, oc:%d", + p_data->api_open.use_rc, p_data->api_open.switch_res, bta_av_cb.audio_open_cnt); + + memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN)); + + switch (p_data->api_open.switch_res) { + case BTA_AV_RS_NONE: + if (bta_av_switch_if_needed(p_scb) || !bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT)) { + /* waiting for role switch result. save the api to control block */ + memcpy(&p_scb->q_info.open, &p_data->api_open, sizeof(tBTA_AV_API_OPEN)); + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN; + p_scb->q_tag = BTA_AV_Q_TAG_OPEN; + } else { + ok_continue = TRUE; + } + break; + + case BTA_AV_RS_FAIL: + /* report a new failure event */ + p_scb->open_status = BTA_AV_FAIL_ROLE; + bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_FAIL_EVT, NULL); + break; + + case BTA_AV_RS_OK: + p_data = (tBTA_AV_DATA *)&p_scb->q_info.open; + /* continue to open if link role is ok */ + if (bta_av_link_role_ok(p_scb, A2D_SET_MULTL_BIT)) { + ok_continue = TRUE; + } else { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_OPEN; + } + break; + + case BTA_AV_RS_DONE: + ok_continue = TRUE; + break; + } + + APPL_TRACE_DEBUG("ok_continue: %d wait:x%x, q_tag: %d", ok_continue, p_scb->wait, p_scb->q_tag); + if (!ok_continue) { + return; + } + + /* clear the role switch bits */ + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + + if (p_scb->wait & BTA_AV_WAIT_CHECK_RC) { + p_scb->wait &= ~BTA_AV_WAIT_CHECK_RC; + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL); + } + + if (bta_av_cb.features & BTA_AV_FEAT_MASTER) { + L2CA_SetDesireRole(L2CAP_ROLE_DISALLOW_SWITCH); + + if (bta_av_cb.audio_open_cnt == 1) { + /* there's already an A2DP connection. do not allow switch */ + bta_sys_clear_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH); + } + } + /* store peer addr other parameters */ + bta_av_save_addr(p_scb, p_data->api_open.bd_addr); + p_scb->sec_mask = p_data->api_open.sec_mask; + p_scb->use_rc = p_data->api_open.use_rc; + + bta_sys_app_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + + /* allocate discovery database */ + if (p_scb->p_disc_db == NULL) { + p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE); + } + + /* only one A2D find service is active at a time */ + bta_av_cb.handle = p_scb->hndl; + + if (p_scb->p_disc_db) { + /* set up parameters */ + db_params.db_len = BTA_AV_DISC_BUF_SIZE; + db_params.num_attr = 3; + db_params.p_db = p_scb->p_disc_db; + db_params.p_attrs = attr_list; + p_scb->uuid_int = p_data->api_open.uuid; + if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SINK) { + sdp_uuid = UUID_SERVCLASS_AUDIO_SOURCE; + } else if (p_scb->uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) { + sdp_uuid = UUID_SERVCLASS_AUDIO_SINK; + } + + APPL_TRACE_DEBUG("uuid_int 0x%x, Doing SDP For 0x%x", p_scb->uuid_int, sdp_uuid); + if (A2D_FindService(sdp_uuid, p_scb->peer_addr, &db_params, + bta_av_a2d_sdp_cback) == A2D_SUCCESS) { + return; + } + } + + /* when the code reaches here, either the DB is NULL + * or A2D_FindService is not successful */ + bta_av_a2d_sdp_cback(FALSE, NULL); +} + +/******************************************************************************* +** +** Function bta_av_cleanup +** +** Description cleanup AV stream control block. +** +** Returns void +** +*******************************************************************************/ +void bta_av_cleanup(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_CONN_CHG msg; + int xx; + UINT8 role = BTA_AV_ROLE_AD_INT; + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_cleanup"); + + /* free any buffers */ + utl_freebuf((void **) &p_scb->p_cap); + utl_freebuf((void **) &p_scb->p_disc_db); + p_scb->avdt_version = 0; + + /* initialize some control block variables */ + p_scb->open_status = BTA_AV_SUCCESS; + + /* if de-registering shut everything down */ + msg.hdr.layer_specific = p_scb->hndl; + p_scb->started = FALSE; + p_scb->cong = FALSE; + p_scb->role = role; + p_scb->cur_psc_mask = 0; + p_scb->wait = 0; + p_scb->num_disc_snks = 0; + p_scb->disc_rsn = 0; + bta_sys_stop_timer(&p_scb->timer); + if (p_scb->deregistring) { + /* remove stream */ + for (xx = 0; xx < BTA_AV_MAX_SEPS; xx++) { + if (p_scb->seps[xx].av_handle) { + AVDT_RemoveStream(p_scb->seps[xx].av_handle); + } + p_scb->seps[xx].av_handle = 0; + } + + bta_av_dereg_comp((tBTA_AV_DATA *) &msg); + } else { + /* report stream closed to main SM */ + msg.is_up = FALSE; + bdcpy(msg.peer_addr, p_scb->peer_addr); + bta_av_conn_chg((tBTA_AV_DATA *) &msg); + } +} + +/******************************************************************************* +** +** Function bta_av_free_sdb +** +** Description Free service discovery db buffer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_free_sdb(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + utl_freebuf((void **) &p_scb->p_disc_db); +} + +/******************************************************************************* +** +** Function bta_av_config_ind +** +** Description Handle a stream configuration indication from the peer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_CI_SETCONFIG setconfig; + tAVDT_SEP_INFO *p_info; + tAVDT_CFG *p_evt_cfg = &p_data->str_msg.cfg; + UINT8 psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask); + UINT8 local_sep; /* sep type of local handle on which connection was received */ + tBTA_AV_STR_MSG *p_msg = (tBTA_AV_STR_MSG *)p_data; + UNUSED(p_data); + + local_sep = bta_av_get_scb_sep_type(p_scb, p_msg->handle); + p_scb->avdt_label = p_data->str_msg.msg.hdr.label; + memcpy(p_scb->cfg.codec_info, p_evt_cfg->codec_info, AVDT_CODEC_SIZE); + p_scb->codec_type = p_evt_cfg->codec_info[BTA_AV_CODEC_TYPE_IDX]; + bta_av_save_addr(p_scb, p_data->str_msg.bd_addr); + + /* Clear collision mask */ + p_scb->coll_mask = 0; + bta_sys_stop_timer(&bta_av_cb.acp_sig_tmr); + + /* if no codec parameters in configuration, fail */ + if ((p_evt_cfg->num_codec == 0) || + /* or the peer requests for a service we do not support */ + ((psc_mask != p_scb->cfg.psc_mask) && + (psc_mask != (p_scb->cfg.psc_mask & ~AVDT_PSC_DELAY_RPT))) ) { + setconfig.hndl = p_scb->hndl; /* we may not need this */ + setconfig.err_code = AVDT_ERR_UNSUP_CFG; + bta_av_ssm_execute(p_scb, BTA_AV_CI_SETCONFIG_FAIL_EVT, (tBTA_AV_DATA *) &setconfig); + } else { + p_info = &p_scb->sep_info[0]; + p_info->in_use = 0; + p_info->media_type = p_scb->media_type; + p_info->seid = p_data->str_msg.msg.config_ind.int_seid; + + /* Sep type of Peer will be oppsite role to our local sep */ + if (local_sep == AVDT_TSEP_SRC) { + p_info->tsep = AVDT_TSEP_SNK; + } else if (local_sep == AVDT_TSEP_SNK) { + p_info->tsep = AVDT_TSEP_SRC; + } + + p_scb->role |= BTA_AV_ROLE_AD_ACP; + p_scb->cur_psc_mask = p_evt_cfg->psc_mask; + if (bta_av_cb.features & BTA_AV_FEAT_RCTG) { + p_scb->use_rc = TRUE; + } else { + p_scb->use_rc = FALSE; + } + + p_scb->num_seps = 1; + p_scb->sep_info_idx = 0; + APPL_TRACE_DEBUG("bta_av_config_ind: SEID: %d use_rc: %d cur_psc_mask:0x%x", p_info->seid, p_scb->use_rc, p_scb->cur_psc_mask); + /* in case of A2DP SINK this is the first time peer data is being sent to co functions */ + if (local_sep == AVDT_TSEP_SNK) { + p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type, + p_evt_cfg->codec_info, + p_info->seid, + p_scb->peer_addr, + p_evt_cfg->num_protect, + p_evt_cfg->protect_info, + AVDT_TSEP_SNK, + p_msg->handle); + } else { + p_scb->p_cos->setcfg(p_scb->hndl, p_scb->codec_type, + p_evt_cfg->codec_info, + p_info->seid, + p_scb->peer_addr, + p_evt_cfg->num_protect, + p_evt_cfg->protect_info, + AVDT_TSEP_SRC, + p_msg->handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_disconnect_req +** +** Description Disconnect AVDTP connection. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_disconnect_req conn_lcb: 0x%x", bta_av_cb.conn_lcb); + + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + bta_sys_stop_timer(&p_scb->timer); + if (bta_av_cb.conn_lcb) { + p_rcb = bta_av_get_rcb_by_shdl((UINT8)(p_scb->hdi + 1)); + if (p_rcb) { + bta_av_del_rc(p_rcb); + } + AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); + } else { + bta_av_ssm_execute(p_scb, BTA_AV_AVDT_DISCONNECT_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function bta_av_security_req +** +** Description Send an AVDTP security request. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) { + AVDT_SecurityReq(p_scb->avdt_handle, p_data->api_protect_req.p_data, + p_data->api_protect_req.len); + } +} + +/******************************************************************************* +** +** Function bta_av_security_rsp +** +** Description Send an AVDTP security response. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) { + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->api_protect_rsp.error_code, + p_data->api_protect_rsp.p_data, p_data->api_protect_rsp.len); + } else { + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, + NULL, 0); + } +} + +/******************************************************************************* +** +** Function bta_av_setconfig_rsp +** +** Description setconfig is OK +** +** Returns void +** +*******************************************************************************/ +void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 num = p_data->ci_setconfig.num_seid + 1; + UINT8 avdt_handle = p_data->ci_setconfig.avdt_handle; + UINT8 *p_seid = p_data->ci_setconfig.p_seid; + int i; + UINT8 local_sep; + + /* we like this codec_type. find the sep_idx */ + local_sep = bta_av_get_scb_sep_type(p_scb, avdt_handle); + bta_av_adjust_seps_idx(p_scb, avdt_handle); + APPL_TRACE_DEBUG("bta_av_setconfig_rsp: sep_idx: %d cur_psc_mask:0x%x", p_scb->sep_idx, p_scb->cur_psc_mask); + + if ((AVDT_TSEP_SNK == local_sep) && (p_data->ci_setconfig.err_code == AVDT_SUCCESS) && + (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT, + (tBTA_AV_MEDIA *)p_scb->cfg.codec_info); + + + AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code, + p_data->ci_setconfig.category); + + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + + if (p_data->ci_setconfig.err_code == AVDT_SUCCESS) { + p_scb->wait = BTA_AV_WAIT_ACP_CAPS_ON; + if (p_data->ci_setconfig.recfg_needed) { + p_scb->role |= BTA_AV_ROLE_SUSPEND_OPT; + } + APPL_TRACE_DEBUG("bta_av_setconfig_rsp recfg_needed:%d role:x%x num:%d", + p_data->ci_setconfig.recfg_needed, p_scb->role, num); + /* callout module tells BTA the number of "good" SEPs and their SEIDs. + * getcap on these SEID */ + p_scb->num_seps = num; + + if (p_scb->cur_psc_mask & AVDT_PSC_DELAY_RPT) { + p_scb->avdt_version = AVDT_VERSION_SYNC; + } + + + if (p_scb->codec_type == BTA_AV_CODEC_SBC || num > 1) { + /* if SBC is used by the SNK as INT, discover req is not sent in bta_av_config_ind. + * call disc_res now */ + /* this is called in A2DP SRC path only, In case of SINK we don't need it */ + if (local_sep == AVDT_TSEP_SRC) + p_scb->p_cos->disc_res(p_scb->hndl, num, num, 0, p_scb->peer_addr, + UUID_SERVCLASS_AUDIO_SOURCE); + } else { + /* we do not know the peer device and it is using non-SBC codec + * we need to know all the SEPs on SNK */ + bta_av_discover_req(p_scb, NULL); + return; + } + + for (i = 1; i < num; i++) { + APPL_TRACE_DEBUG("sep_info[%d] SEID: %d", i, p_seid[i - 1]); + /* initialize the sep_info[] to get capabilities */ + p_scb->sep_info[i].in_use = FALSE; + p_scb->sep_info[i].tsep = AVDT_TSEP_SNK; + p_scb->sep_info[i].media_type = p_scb->media_type; + p_scb->sep_info[i].seid = p_seid[i - 1]; + } + + /* only in case of local sep as SRC we need to look for other SEPs, In case of SINK we don't */ + if (local_sep == AVDT_TSEP_SRC) { + /* Make sure UUID has been initialized... */ + if (p_scb->uuid_int == 0) { + p_scb->uuid_int = p_scb->open_api.uuid; + } + bta_av_next_getcap(p_scb, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_av_str_opened +** +** Description Stream opened OK (incoming/outgoing). +** +** Returns void +** +*******************************************************************************/ +void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_CONN_CHG msg; + tBTA_AV_OPEN open; + UINT8 *p; + UINT16 mtu; + + msg.hdr.layer_specific = p_scb->hndl; + msg.is_up = TRUE; + bdcpy(msg.peer_addr, p_scb->peer_addr); + p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle); + bta_av_conn_chg((tBTA_AV_DATA *) &msg); + /* set the congestion flag, so AV would not send media packets by accident */ + p_scb->cong = TRUE; + + + p_scb->stream_mtu = p_data->str_msg.msg.open_ind.peer_mtu - AVDT_MEDIA_HDR_SIZE; + mtu = bta_av_chk_mtu(p_scb, p_scb->stream_mtu); + APPL_TRACE_DEBUG("bta_av_str_opened l2c_cid: 0x%x stream_mtu: %d mtu: %d", + p_scb->l2c_cid, p_scb->stream_mtu, mtu); + if (mtu == 0 || mtu > p_scb->stream_mtu) { + mtu = p_scb->stream_mtu; + } + + /* Set the media channel as medium priority */ + L2CA_SetTxPriority(p_scb->l2c_cid, L2CAP_CHNL_PRIORITY_MEDIUM); + L2CA_SetChnlFlushability (p_scb->l2c_cid, TRUE); + + bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + memset(&p_scb->q_info, 0, sizeof(tBTA_AV_Q_INFO)); + + p_scb->l2c_bufs = 0; + p_scb->p_cos->open(p_scb->hndl, + p_scb->codec_type, p_scb->cfg.codec_info, mtu); + + { + /* TODO check if other audio channel is open. + * If yes, check if reconfig is needed + * Rigt now we do not do this kind of checking. + * BTA-AV is INT for 2nd audio connection. + * The application needs to make sure the current codec_info is proper. + * If one audio connection is open and another SNK attempts to connect to AV, + * the connection will be rejected. + */ + /* check if other audio channel is started. If yes, start */ + bdcpy(open.bd_addr, p_scb->peer_addr); + open.chnl = p_scb->chnl; + open.hndl = p_scb->hndl; + open.status = BTA_AV_SUCCESS; + open.starting = bta_av_chk_start(p_scb); + open.edr = 0; + if ( NULL != (p = BTM_ReadRemoteFeatures(p_scb->peer_addr))) { + if (HCI_EDR_ACL_2MPS_SUPPORTED(p)) { + open.edr |= BTA_AV_EDR_2MBPS; + } + if (HCI_EDR_ACL_3MPS_SUPPORTED(p)) { + open.edr |= BTA_AV_EDR_3MBPS; + } + } +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr); +#endif + if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) { + open.sep = AVDT_TSEP_SNK; + } else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) { + open.sep = AVDT_TSEP_SRC; + } + + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open); + if (open.starting) { + bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL); + } + } + +#if 0 /* TODO: implement the property enable/disable */ + // This code is used to pass PTS TC for AVDTP ABORT + char value[PROPERTY_VALUE_MAX] = {0}; + if ((property_get("bluetooth.pts.force_a2dp_abort", value, "false")) + && (!strcmp(value, "true"))) { + APPL_TRACE_ERROR ("%s: Calling AVDT_AbortReq", __func__); + AVDT_AbortReq(p_scb->avdt_handle); + } +#endif /* #if 0*/ +} + +/******************************************************************************* +** +** Function bta_av_security_ind +** +** Description Handle an AVDTP security indication. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_PROTECT_REQ protect_req; + + p_scb->avdt_label = p_data->str_msg.msg.hdr.label; + + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) { + protect_req.chnl = p_scb->chnl; + protect_req.hndl = p_scb->hndl; + /* + APPL_TRACE_EVENT("sec ind handle: x%x", protect_req.hndl); + */ + protect_req.p_data = p_data->str_msg.msg.security_ind.p_data; + protect_req.len = p_data->str_msg.msg.security_ind.len; + + (*bta_av_cb.p_cback)(BTA_AV_PROTECT_REQ_EVT, (tBTA_AV *) &protect_req); + } + /* app doesn't support security indication; respond with failure */ + else { + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_NSC, NULL, 0); + } +} + +/******************************************************************************* +** +** Function bta_av_security_cfm +** +** Description Handle an AVDTP security confirm. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_PROTECT_RSP protect_rsp; + + if (bta_av_cb.features & BTA_AV_FEAT_PROTECT) { + protect_rsp.chnl = p_scb->chnl; + protect_rsp.hndl = p_scb->hndl; + protect_rsp.p_data = p_data->str_msg.msg.security_cfm.p_data; + protect_rsp.len = p_data->str_msg.msg.security_cfm.len; + protect_rsp.err_code = p_data->str_msg.msg.hdr.err_code; + + (*bta_av_cb.p_cback)(BTA_AV_PROTECT_RSP_EVT, (tBTA_AV *) &protect_rsp); + } +} + +/******************************************************************************* +** +** Function bta_av_do_close +** +** Description Close stream. +** +** Returns void +** +*******************************************************************************/ +void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + /* stop stream if started */ + if (p_scb->co_started) { + bta_av_str_stopped(p_scb, NULL); + } + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + + /* close stream */ + p_scb->started = FALSE; + + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + + AVDT_CloseReq(p_scb->avdt_handle); + /* just in case that the link is congested, link is flow controled by peer or + * for whatever reason the the close request can not be sent in time. + * when this timer expires, AVDT_DisconnectReq will be called to disconnect the link + */ + bta_sys_start_timer(&p_scb->timer, + (UINT16)BTA_AV_API_CLOSE_EVT, + BTA_AV_CLOSE_REQ_TIME_VAL); + +} + +/******************************************************************************* +** +** Function bta_av_connect_req +** +** Description Connect AVDTP connection. +** +** Returns void +** +*******************************************************************************/ +void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + utl_freebuf((void **) &p_scb->p_disc_db); + + if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) { + /* SNK initiated L2C connection while SRC was doing SDP. */ + /* Wait until timeout to check if SNK starts signalling. */ + APPL_TRACE_EVENT("bta_av_connect_req: coll_mask = 0x%2X", p_scb->coll_mask); + return; + } + + AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]); +} + +/******************************************************************************* +** +** Function bta_av_sdp_failed +** +** Description Service discovery failed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + if (!p_scb->open_status) { + p_scb->open_status = BTA_AV_FAIL_SDP; + } + + utl_freebuf((void **) &p_scb->p_disc_db); + bta_av_str_closed(p_scb, p_data); +} + +/******************************************************************************* +** +** Function bta_av_disc_results +** +** Description Handle the AVDTP discover results. Search through the +** results and find the first available stream, and get +** its capabilities. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 num_snks = 0, num_srcs = 0, i; + /* our uuid in case we initiate connection */ + UINT16 uuid_int = p_scb->uuid_int; + + APPL_TRACE_DEBUG(" initiator UUID 0x%x", uuid_int); + /* store number of stream endpoints returned */ + p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps; + + for (i = 0; i < p_scb->num_seps; i++) { + /* steam not in use, is a sink, and is audio */ + if ((p_scb->sep_info[i].in_use == FALSE) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) { + if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE)) { + num_snks++; + } + + if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SRC) && + (uuid_int == UUID_SERVCLASS_AUDIO_SINK)) { + num_srcs++; + } + + } + } + + p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, num_srcs, p_scb->peer_addr, + uuid_int); + p_scb->num_disc_snks = num_snks; + p_scb->num_disc_srcs = num_srcs; + + /* if we got any */ + if (p_scb->num_seps > 0) { + /* initialize index into discovery results */ + p_scb->sep_info_idx = 0; + + /* get the capabilities of the first available stream */ + bta_av_next_getcap(p_scb, p_data); + } + /* else we got discover response but with no streams; we're done */ + else { + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_disc_res_as_acp +** +** Description Handle the AVDTP discover results. Search through the +** results and find the first available stream, and get +** its capabilities. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 num_snks = 0, i; + + /* store number of stream endpoints returned */ + p_scb->num_seps = p_data->str_msg.msg.discover_cfm.num_seps; + + + + for (i = 0; i < p_scb->num_seps; i++) { + /* steam is a sink, and is audio */ + if ((p_scb->sep_info[i].tsep == AVDT_TSEP_SNK) && + (p_scb->sep_info[i].media_type == p_scb->media_type)) { + p_scb->sep_info[i].in_use = FALSE; + num_snks++; + } + } + p_scb->p_cos->disc_res(p_scb->hndl, p_scb->num_seps, num_snks, 0, p_scb->peer_addr, + UUID_SERVCLASS_AUDIO_SOURCE); + p_scb->num_disc_snks = num_snks; + p_scb->num_disc_srcs = 0; + + /* if we got any */ + if (p_scb->num_seps > 0) { + /* initialize index into discovery results */ + p_scb->sep_info_idx = 0; + + /* get the capabilities of the first available stream */ + bta_av_next_getcap(p_scb, p_data); + } + /* else we got discover response but with no streams; we're done */ + else { + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_save_caps +** +** Description report the SNK SEP capabilities to application +** +** Returns void +** +*******************************************************************************/ +void bta_av_save_caps(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tAVDT_CFG cfg; + tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx]; + UINT8 old_wait = p_scb->wait; + BOOLEAN getcap_done = FALSE; + + APPL_TRACE_DEBUG("bta_av_save_caps num_seps:%d sep_info_idx:%d wait:x%x", + p_scb->num_seps, p_scb->sep_info_idx, p_scb->wait); + memcpy(&cfg, p_scb->p_cap, sizeof(tAVDT_CFG)); + /* let application know the capability of the SNK */ + p_scb->p_cos->getcfg(p_scb->hndl, cfg.codec_info[BTA_AV_CODEC_TYPE_IDX], + cfg.codec_info, &p_scb->sep_info_idx, p_info->seid, + &cfg.num_protect, cfg.protect_info); + + p_scb->sep_info_idx++; + if (p_scb->num_seps > p_scb->sep_info_idx) { + /* Some devices have seps at the end of the discover list, which is not */ + /* matching media type(video not audio). */ + /* In this case, we are done with getcap without sending another */ + /* request to AVDT. */ + if (!bta_av_next_getcap(p_scb, p_data)) { + getcap_done = TRUE; + } + } else { + getcap_done = TRUE; + } + + if (getcap_done) { + /* we are done getting capabilities. restore the p_cb->sep_info_idx */ + p_scb->sep_info_idx = 0; + p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON | BTA_AV_WAIT_ACP_CAPS_STARTED); + if (old_wait & BTA_AV_WAIT_ACP_CAPS_STARTED) { + bta_av_start_ok (p_scb, NULL); + } + } +} + +/******************************************************************************* +** +** Function bta_av_set_use_rc +** +** Description set to use AVRC for this stream control block. +** +** Returns void +** +*******************************************************************************/ +void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + p_scb->use_rc = TRUE; +} + +/******************************************************************************* +** +** Function bta_av_cco_close +** +** Description call close call-out function. +** +** Returns void +** +*******************************************************************************/ +void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT16 mtu; + UNUSED(p_data); + + mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU); + + p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu); +} + +/******************************************************************************* +** +** Function bta_av_open_failed +** +** Description Failed to open an AVDT stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + + BOOLEAN is_av_opened = FALSE; + tBTA_AV_SCB *p_opened_scb = NULL; + UINT8 idx; + tBTA_AV_OPEN open; + + APPL_TRACE_DEBUG("bta_av_open_failed"); + p_scb->open_status = BTA_AV_FAIL_STREAM; + bta_av_cco_close(p_scb, p_data); + + /* check whether there is already an opened audio or video connection with the same device */ + for (idx = 0; (idx < BTA_AV_NUM_STRS) && (is_av_opened == FALSE); idx++ ) { + p_opened_scb = bta_av_cb.p_scb[idx]; + if (p_opened_scb && (p_opened_scb->state == BTA_AV_OPEN_SST) && (!bdcmp(p_opened_scb->peer_addr, p_scb->peer_addr )) ) { + is_av_opened = TRUE; + } + + } + + /* if there is already an active AV connnection with the same bd_addr, + don't send disconnect req, just report the open event with BTA_AV_FAIL_GET_CAP status */ + if (is_av_opened == TRUE) { + bdcpy(open.bd_addr, p_scb->peer_addr); + open.chnl = p_scb->chnl; + open.hndl = p_scb->hndl; + open.status = BTA_AV_FAIL_GET_CAP; + open.starting = bta_av_chk_start(p_scb); + open.edr = 0; + /* set the state back to initial state */ + bta_av_set_scb_sst_init(p_scb); + + if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) { + open.sep = AVDT_TSEP_SNK; + } else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) { + open.sep = AVDT_TSEP_SRC; + } + + (*bta_av_cb.p_cback)(BTA_AV_OPEN_EVT, (tBTA_AV *) &open); + + } else { + AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); + } +} + + +/******************************************************************************* +** +** Function bta_av_getcap_results +** +** Description Handle the AVDTP get capabilities results. Check the codec +** type and see if it matches ours. If it does not, get the +** capabilities of the next stream, if any. +** +** Returns void +** +*******************************************************************************/ +void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tAVDT_CFG cfg; + UINT8 media_type; + tAVDT_SEP_INFO *p_info = &p_scb->sep_info[p_scb->sep_info_idx]; + UINT16 uuid_int; /* UUID for which connection was initiatied */ + + memcpy(&cfg, &p_scb->cfg, sizeof(tAVDT_CFG)); + cfg.num_codec = 1; + cfg.num_protect = p_scb->p_cap->num_protect; + memcpy(cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE); + memcpy(cfg.protect_info, p_scb->p_cap->protect_info, AVDT_PROTECT_SIZE); + media_type = p_scb->p_cap->codec_info[BTA_AV_MEDIA_TYPE_IDX] >> 4; + + APPL_TRACE_DEBUG("num_codec %d", p_scb->p_cap->num_codec); + APPL_TRACE_DEBUG("media type x%x, x%x", media_type, p_scb->media_type); +#if AVDT_MULTIPLEXING == TRUE + APPL_TRACE_DEBUG("mux x%x, x%x", cfg.mux_mask, p_scb->p_cap->mux_mask); +#endif + + /* if codec present and we get a codec configuration */ + if ((p_scb->p_cap->num_codec != 0) && + (media_type == p_scb->media_type) && + (p_scb->p_cos->getcfg(p_scb->hndl, p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX], + cfg.codec_info, &p_scb->sep_info_idx, p_info->seid, + &cfg.num_protect, cfg.protect_info) == 0)) { +#if AVDT_MULTIPLEXING == TRUE + cfg.mux_mask &= p_scb->p_cap->mux_mask; + APPL_TRACE_DEBUG("mux_mask used x%x", cfg.mux_mask); +#endif + /* save copy of codec type and configuration */ + p_scb->codec_type = cfg.codec_info[BTA_AV_CODEC_TYPE_IDX]; + memcpy(&p_scb->cfg, &cfg, sizeof(tAVDT_CFG)); + + uuid_int = p_scb->uuid_int; + APPL_TRACE_DEBUG(" initiator UUID = 0x%x ", uuid_int); + if (uuid_int == UUID_SERVCLASS_AUDIO_SOURCE) { + bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC)); + } else if (uuid_int == UUID_SERVCLASS_AUDIO_SINK) { + bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SNK)); + } + + /* use only the services peer supports */ + cfg.psc_mask &= p_scb->p_cap->psc_mask; + p_scb->cur_psc_mask = cfg.psc_mask; + + if ((uuid_int == UUID_SERVCLASS_AUDIO_SINK) && + (p_scb->seps[p_scb->sep_idx].p_app_data_cback != NULL)) { + APPL_TRACE_DEBUG(" Configure Deoder for Sink Connection "); + p_scb->seps[p_scb->sep_idx].p_app_data_cback(BTA_AV_MEDIA_SINK_CFG_EVT, + (tBTA_AV_MEDIA *)p_scb->cfg.codec_info); + } + + /* open the stream */ + AVDT_OpenReq(p_scb->seps[p_scb->sep_idx].av_handle, p_scb->peer_addr, + p_scb->sep_info[p_scb->sep_info_idx].seid, &cfg); + + if (!bta_av_is_rcfg_sst(p_scb)) { + /* free capabilities buffer */ + utl_freebuf((void **) &p_scb->p_cap); + } + } else { + /* try the next stream, if any */ + p_scb->sep_info_idx++; + bta_av_next_getcap(p_scb, p_data); + } + +} + +/******************************************************************************* +** +** Function bta_av_setconfig_rej +** +** Description Send AVDTP set config reject. +** +** Returns void +** +*******************************************************************************/ +void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_REJECT reject; + UINT8 avdt_handle = p_data->ci_setconfig.avdt_handle; + + bta_av_adjust_seps_idx(p_scb, avdt_handle); + APPL_TRACE_DEBUG("bta_av_setconfig_rej: sep_idx: %d", p_scb->sep_idx); + AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_UNSUP_CFG, 0); + + bdcpy(reject.bd_addr, p_data->str_msg.bd_addr); + reject.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject); +} + +/******************************************************************************* +** +** Function bta_av_discover_req +** +** Description Send an AVDTP discover request to the peer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + /* send avdtp discover request */ + + AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]); +} + +/******************************************************************************* +** +** Function bta_av_conn_failed +** +** Description AVDTP connection failed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + p_scb->open_status = BTA_AV_FAIL_STREAM; + bta_av_str_closed(p_scb, p_data); +} + +/******************************************************************************* +** +** Function bta_av_do_start +** +** Description Start stream. +** +** Returns void +** +*******************************************************************************/ +void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + UINT8 cur_role; + + APPL_TRACE_DEBUG("bta_av_do_start sco_occupied:%d, role:x%x, started:%d", bta_av_cb.sco_occupied, p_scb->role, p_scb->started); + if (bta_av_cb.sco_occupied) { + bta_av_start_failed(p_scb, p_data); + return; + } + + /* disallow role switch during streaming, only if we are the master role + * i.e. allow role switch, if we are slave. + * It would not hurt us, if the peer device wants us to be master */ + if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) && + (cur_role == BTM_ROLE_MASTER) ) { + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + } + + bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr); + + if ((p_scb->started == FALSE) && ((p_scb->role & BTA_AV_ROLE_START_INT) == 0)) { + p_scb->role |= BTA_AV_ROLE_START_INT; + bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + + AVDT_StartReq(&p_scb->avdt_handle, 1); + } else if (p_scb->started) { + p_scb->role |= BTA_AV_ROLE_START_INT; + if ( p_scb->wait == 0 ) { + if (p_scb->role & BTA_AV_ROLE_SUSPEND) { + notify_start_failed(p_scb); + } else { + bta_av_start_ok(p_scb, NULL); + } + } + } + APPL_TRACE_DEBUG("started %d role:x%x", p_scb->started, p_scb->role); +} + +/******************************************************************************* +** +** Function bta_av_str_stopped +** +** Description Stream stopped. +** +** Returns void +** +*******************************************************************************/ +void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SUSPEND suspend_rsp; + UINT8 start = p_scb->started; + BOOLEAN sus_evt = TRUE; + BT_HDR *p_buf; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + + APPL_TRACE_ERROR("bta_av_str_stopped:audio_open_cnt=%d, p_data %p", + bta_av_cb.audio_open_cnt, p_data); + + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1) { + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + } + bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr); + + if (p_scb->co_started) { + bta_av_stream_chg(p_scb, FALSE); + p_scb->co_started = FALSE; + + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO); + } + + /* if q_info.a2d_list is not empty, drop it now */ + if (BTA_AV_CHNL_AUDIO == p_scb->chnl) { + while (!list_is_empty(p_scb->a2d_list)) { + p_buf = (BT_HDR *)list_front(p_scb->a2d_list); + list_remove(p_scb->a2d_list, p_buf); + GKI_freebuf(p_buf); + } + + /* drop the audio buffers queued in L2CAP */ + if (p_data && p_data->api_stop.flush) { + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + } + } + + suspend_rsp.chnl = p_scb->chnl; + suspend_rsp.hndl = p_scb->hndl; + + if (p_data && p_data->api_stop.suspend) { + APPL_TRACE_DEBUG("suspending: %d, sup:%d", start, p_scb->suspend_sup); + if ((start) && (p_scb->suspend_sup)) { + sus_evt = FALSE; + p_scb->l2c_bufs = 0; + AVDT_SuspendReq(&p_scb->avdt_handle, 1); + } + + /* send SUSPEND_EVT event only if not in reconfiguring state and sus_evt is TRUE*/ + if ((sus_evt) && (p_scb->state != BTA_AV_RCFG_SST)) { + suspend_rsp.status = BTA_AV_SUCCESS; + suspend_rsp.initiator = TRUE; + (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp); + } + } else { + suspend_rsp.status = BTA_AV_SUCCESS; + suspend_rsp.initiator = TRUE; + APPL_TRACE_EVENT("bta_av_str_stopped status %d", suspend_rsp.status); + + /* send STOP_EVT event only if not in reconfiguring state */ + if (p_scb->state != BTA_AV_RCFG_SST) { + (*bta_av_cb.p_cback)(BTA_AV_STOP_EVT, (tBTA_AV *) &suspend_rsp); + } + } +} + +/******************************************************************************* +** +** Function bta_av_reconfig +** +** Description process the reconfigure request. +** save the parameter in control block and +** suspend, reconfigure or close the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tAVDT_CFG *p_cfg; + tBTA_AV_API_STOP stop; + tBTA_AV_RECONFIG evt; + tBTA_AV_API_RCFG *p_rcfg = &p_data->api_reconfig; + + APPL_TRACE_DEBUG("bta_av_reconfig r:%d, s:%d idx: %d (o:%d)", + p_scb->recfg_sup, p_scb->suspend_sup, + p_scb->rcfg_idx, p_scb->sep_info_idx); + + p_scb->num_recfg = 0; + /* store the new configuration in control block */ + if (p_scb->p_cap == NULL) { + p_scb->p_cap = (tAVDT_CFG *) GKI_getbuf(sizeof(tAVDT_CFG)); + } + if ((p_cfg = p_scb->p_cap) == NULL) { + /* report failure */ + evt.status = BTA_AV_FAIL_RESOURCES; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + + /* this event is not possible in this state. + * use it to bring the SSM back to open state */ + bta_av_ssm_execute(p_scb, BTA_AV_SDP_DISC_OK_EVT, NULL); + return; + } + + /*if(bta_av_cb.features & BTA_AV_FEAT_RCCT)*/ + bta_sys_stop_timer(&p_scb->timer); + + memcpy(p_cfg, &p_scb->cfg, sizeof(tAVDT_CFG)); + p_cfg->num_protect = p_rcfg->num_protect; + memcpy(p_cfg->codec_info, p_rcfg->codec_info, AVDT_CODEC_SIZE); + memcpy(p_cfg->protect_info, p_rcfg->p_protect_info, p_rcfg->num_protect); + p_scb->rcfg_idx = p_rcfg->sep_info_idx; + p_scb->p_cap->psc_mask = p_scb->cur_psc_mask; + + /* if the requested index differs from the current one, we can only close/open */ + if ((p_scb->rcfg_idx == p_scb->sep_info_idx) && + (p_rcfg->suspend) && (p_scb->recfg_sup) && (p_scb->suspend_sup)) { + if (p_scb->started) { + stop.flush = FALSE; + stop.suspend = TRUE; + bta_av_str_stopped(p_scb, (tBTA_AV_DATA *)&stop); + } else { + APPL_TRACE_DEBUG("Reconfig"); + AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap); + p_scb->p_cap->psc_mask = p_scb->cur_psc_mask; + } + } else { + /* close the stream */ + APPL_TRACE_DEBUG("close/open num_protect: %d", p_cfg->num_protect); + if (p_scb->started) { + bta_av_str_stopped(p_scb, NULL); + p_scb->started = FALSE; + + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + + AVDT_CloseReq(p_scb->avdt_handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_data_path +** +** Description Handle stream data path. +** +** Returns void +** +*******************************************************************************/ +void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + BT_HDR *p_buf = NULL; + UINT32 data_len; + UINT32 timestamp; + BOOLEAN new_buf = FALSE; + UINT8 m_pt = 0x60 | p_scb->codec_type; + tAVDT_DATA_OPT_MASK opt; + UNUSED(p_data); + + if (p_scb->cong) { + return; + } + + /* + APPL_TRACE_ERROR("q: %d", p_scb->l2c_bufs); + */ + //Always get the current number of bufs que'd up + p_scb->l2c_bufs = (UINT8)L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_GET); + + if (!list_is_empty(p_scb->a2d_list)) { + p_buf = (BT_HDR *)list_front(p_scb->a2d_list); + list_remove(p_scb->a2d_list, p_buf); + /* use q_info.a2d data, read the timestamp */ + timestamp = *(UINT32 *)(p_buf + 1); + } else { + new_buf = TRUE; + /* a2d_list empty, call co_data, dup data to other channels */ + p_buf = (BT_HDR *)p_scb->p_cos->data(p_scb->codec_type, &data_len, + ×tamp); + + if (p_buf) { + /* use the offset area for the time stamp */ + *(UINT32 *)(p_buf + 1) = timestamp; + + /* dup the data to other channels */ + bta_av_dup_audio_buf(p_scb, p_buf); + } + } + + if (p_buf) { + if (p_scb->l2c_bufs < (BTA_AV_QUEUE_DATA_CHK_NUM)) { + /* there's a buffer, just queue it to L2CAP */ + /* There's no need to increment it here, it is always read from L2CAP see above */ + /* p_scb->l2c_bufs++; */ + /* + APPL_TRACE_ERROR("qw: %d", p_scb->l2c_bufs); + */ + + /* opt is a bit mask, it could have several options set */ + opt = AVDT_DATA_OPT_NONE; + if (p_scb->no_rtp_hdr) { + opt |= AVDT_DATA_OPT_NO_RTP; + } + + AVDT_WriteReqOpt(p_scb->avdt_handle, p_buf, timestamp, m_pt, opt); + p_scb->cong = TRUE; + } else { + /* there's a buffer, but L2CAP does not seem to be moving data */ + if (new_buf) { + /* just got this buffer from co_data, + * put it in queue */ + list_append(p_scb->a2d_list, p_buf); + } else { + /* just dequeue it from the a2d_list */ + if (list_length(p_scb->a2d_list) < 3) { + /* put it back to the queue */ + list_prepend(p_scb->a2d_list, p_buf); + } else { + /* too many buffers in a2d_list, drop it. */ + bta_av_co_audio_drop(p_scb->hndl); + GKI_freebuf(p_buf); + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_start_ok +** +** Description Stream started. +** +** Returns void +** +*******************************************************************************/ +void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_START start; + tBTA_AV_API_STOP stop; + BOOLEAN initiator = FALSE; + BOOLEAN suspend = FALSE; + UINT16 flush_to; + UINT8 new_role = p_scb->role; + BT_HDR hdr; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + UINT8 cur_role; + + APPL_TRACE_DEBUG("bta_av_start_ok wait:x%x, role:x%x", p_scb->wait, p_scb->role); + + p_scb->started = TRUE; + if (p_scb->sco_suspend) { + p_scb->sco_suspend = FALSE; + } + + if (new_role & BTA_AV_ROLE_START_INT) { + initiator = TRUE; + } + + /* for A2DP SINK we do not send get_caps */ + if ((p_scb->avdt_handle == p_scb->seps[p_scb->sep_idx].av_handle) + && (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK)) { + p_scb->wait &= ~(BTA_AV_WAIT_ACP_CAPS_ON); + APPL_TRACE_DEBUG(" Local SEP type is SNK new wait is 0x%x", p_scb->wait); + } + if (p_scb->wait & BTA_AV_WAIT_ROLE_SW_FAILED) { + /* role switch has failed */ + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_FAILED; + p_data = (tBTA_AV_DATA *)&hdr; + hdr.offset = BTA_AV_RS_FAIL; + } + APPL_TRACE_DEBUG("wait:x%x", p_scb->wait); + + if (p_data && (p_data->hdr.offset != BTA_AV_RS_NONE)) { + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + if (p_data->hdr.offset == BTA_AV_RS_FAIL) { + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL_ROLE; + start.hndl = p_scb->hndl; + start.initiator = initiator; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + return; + } + } + + if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT)) { + p_scb->q_tag = BTA_AV_Q_TAG_START; + } else { + /* The wait flag may be set here while we are already master on the link */ + /* this could happen if a role switch complete event occurred during reconfig */ + /* if we are now master on the link, there is no need to wait for the role switch, */ + /* complete anymore so we can clear the wait for role switch flag */ + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + } + + if (p_scb->wait & (BTA_AV_WAIT_ROLE_SW_RES_OPEN | BTA_AV_WAIT_ROLE_SW_RES_START)) { + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_STARTED; + p_scb->q_tag = BTA_AV_Q_TAG_START; + } + + if (p_scb->wait) { + APPL_TRACE_ERROR("wait:x%x q_tag:%d- not started", p_scb->wait, p_scb->q_tag); + /* Clear first bit of p_scb->wait and not to return from this point else + * HAL layer gets blocked. And if there is delay in Get Capability response as + * first bit of p_scb->wait is cleared hence it ensures bt_av_start_ok is not called + * again from bta_av_save_caps. + */ + p_scb->wait &= ~BTA_AV_WAIT_ACP_CAPS_ON; + } + + /* tell role manager to check M/S role */ + bta_sys_conn_open(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + + bta_sys_busy(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + + if (p_scb->media_type == AVDT_MEDIA_AUDIO) { + /* in normal logic, conns should be bta_av_cb.audio_count - 1, + * However, bta_av_stream_chg is not called to increase bta_av_cb.audio_count yet. + * If the code were to be re-arranged for some reasons, this number may need to be changed + */ + p_scb->co_started = bta_av_cb.audio_open_cnt; + flush_to = p_bta_av_cfg->p_audio_flush_to[p_scb->co_started - 1]; + } else { + flush_to = p_bta_av_cfg->video_flush_to; + } + L2CA_SetFlushTimeout(p_scb->peer_addr, flush_to ); + + /* clear the congestion flag */ + p_scb->cong = FALSE; + + if (new_role & BTA_AV_ROLE_START_INT) { + new_role &= ~BTA_AV_ROLE_START_INT; + } else if ((new_role & BTA_AV_ROLE_AD_ACP) && (new_role & BTA_AV_ROLE_SUSPEND_OPT)) { + suspend = TRUE; + } + + if (!suspend) { + p_scb->q_tag = BTA_AV_Q_TAG_STREAM; + bta_av_stream_chg(p_scb, TRUE); + } + + { + /* If sink starts stream, disable sniff mode here */ + if (!initiator) { + /* If souce is the master role, disable role switch during streaming. + * Otherwise allow role switch, if source is slave. + * Because it would not hurt source, if the peer device wants source to be master */ + if ((BTM_GetRole (p_scb->peer_addr, &cur_role) == BTM_SUCCESS) && + (cur_role == BTM_ROLE_MASTER) ) { + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + } + + bta_sys_clear_policy(BTA_ID_AV, policy, p_scb->peer_addr); + } + + p_scb->role = new_role; + p_scb->role &= ~BTA_AV_ROLE_AD_ACP; + p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT; + + p_scb->no_rtp_hdr = FALSE; + p_scb->p_cos->start(p_scb->hndl, p_scb->codec_type, p_scb->cfg.codec_info, &p_scb->no_rtp_hdr); + p_scb->co_started = TRUE; + + APPL_TRACE_DEBUG("bta_av_start_ok suspending: %d, role:x%x, init %d", + suspend, p_scb->role, initiator); + + start.suspending = suspend; + start.initiator = initiator; + start.chnl = p_scb->chnl; + start.status = BTA_AV_SUCCESS; + start.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + + if (suspend) { + p_scb->role |= BTA_AV_ROLE_SUSPEND; + p_scb->cong = TRUE; /* do not allow the media data to go through */ + /* do not duplicate the media packets to this channel */ + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + p_scb->co_started = FALSE; + stop.flush = FALSE; + stop.suspend = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop); + } + } +} + +/******************************************************************************* +** +** Function bta_av_start_failed +** +** Description Stream start failed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + if (p_scb->started == FALSE && p_scb->co_started == FALSE) { + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + notify_start_failed(p_scb); + } + + bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_SNIFF_MODE | HCI_ENABLE_MASTER_SLAVE_SWITCH), p_scb->peer_addr); + p_scb->sco_suspend = FALSE; +} + +/******************************************************************************* +** +** Function bta_av_str_closed +** +** Description Stream closed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV data; + tBTA_AV_EVT event; + UINT16 mtu; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + + if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1) { + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + } + bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr); + if (bta_av_cb.audio_open_cnt <= 1) { + /* last connection - restore the allow switch flag */ + L2CA_SetDesireRole(L2CAP_ROLE_ALLOW_SWITCH); + } + + if (p_scb->open_status) { + /* must be failure when opening the stream */ + bdcpy(data.open.bd_addr, p_scb->peer_addr); + data.open.status = p_scb->open_status; + data.open.chnl = p_scb->chnl; + data.open.hndl = p_scb->hndl; + + if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC ) { + data.open.sep = AVDT_TSEP_SNK; + } else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK ) { + data.open.sep = AVDT_TSEP_SRC; + } + + event = BTA_AV_OPEN_EVT; + p_scb->open_status = BTA_AV_SUCCESS; + + bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + bta_av_cleanup(p_scb, p_data); + (*bta_av_cb.p_cback)(event, &data); + } else { + /* do stop if we were started */ + if (p_scb->co_started) { + bta_av_str_stopped(p_scb, NULL); + } + + /* Update common mtu shared by remaining connectons */ + mtu = bta_av_chk_mtu(p_scb, BTA_AV_MAX_A2DP_MTU); + + { + p_scb->p_cos->close(p_scb->hndl, p_scb->codec_type, mtu); + data.close.chnl = p_scb->chnl; + data.close.hndl = p_scb->hndl; + data.close.disc_rsn = p_scb->disc_rsn; + event = BTA_AV_CLOSE_EVT; + + bta_sys_conn_close(BTA_ID_AV, p_scb->app_id, p_scb->peer_addr); + bta_av_cleanup(p_scb, p_data); + (*bta_av_cb.p_cback)(event, &data); + } + } +} + +/******************************************************************************* +** +** Function bta_av_clr_cong +** +** Description Clear stream congestion flag. +** +** Returns void +** +*******************************************************************************/ +void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + if (p_scb->co_started) { + p_scb->cong = FALSE; + } +} + +/******************************************************************************* +** +** Function bta_av_suspend_cfm +** +** Description process the suspend response +** +** Returns void +** +*******************************************************************************/ +void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SUSPEND suspend_rsp; + UINT8 err_code = p_data->str_msg.msg.hdr.err_code; + UINT8 policy = HCI_ENABLE_SNIFF_MODE; + + APPL_TRACE_DEBUG ("bta_av_suspend_cfm:audio_open_cnt = %d, err_code = %d", + bta_av_cb.audio_open_cnt, err_code); + + if (p_scb->started == FALSE) { + /* handle the condition where there is a collision of SUSPEND req from either side + ** Second SUSPEND req could be rejected. Do not treat this as a failure + */ + APPL_TRACE_WARNING("bta_av_suspend_cfm: already suspended, ignore, err_code %d", + err_code); + return; + } + + suspend_rsp.status = BTA_AV_SUCCESS; + if (err_code && (err_code != AVDT_ERR_BAD_STATE)) { + /* Disable suspend feature only with explicit rejection(not with timeout) */ + if (err_code != AVDT_ERR_TIMEOUT) { + p_scb->suspend_sup = FALSE; + } + suspend_rsp.status = BTA_AV_FAIL; + + APPL_TRACE_ERROR ("bta_av_suspend_cfm: suspend failed, closing connection"); + + /* SUSPEND failed. Close connection. */ + bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL); + } else { + /* only set started to FALSE when suspend is successful */ + p_scb->started = FALSE; + } + + if (p_scb->role & BTA_AV_ROLE_SUSPEND) { + p_scb->role &= ~BTA_AV_ROLE_SUSPEND; + p_scb->cong = FALSE; + } + + bta_sys_idle(BTA_ID_AV, bta_av_cb.audio_open_cnt, p_scb->peer_addr); + if ((bta_av_cb.features & BTA_AV_FEAT_MASTER) == 0 || bta_av_cb.audio_open_cnt == 1) { + policy |= HCI_ENABLE_MASTER_SLAVE_SWITCH; + } + bta_sys_set_policy(BTA_ID_AV, policy, p_scb->peer_addr); + + /* in case that we received suspend_ind, we may need to call co_stop here */ + if (p_scb->co_started) { + bta_av_stream_chg(p_scb, FALSE); + + { + p_scb->co_started = FALSE; + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + } + L2CA_SetFlushTimeout(p_scb->peer_addr, L2CAP_DEFAULT_FLUSH_TO); + } + + { + suspend_rsp.chnl = p_scb->chnl; + suspend_rsp.hndl = p_scb->hndl; + suspend_rsp.initiator = p_data->str_msg.initiator; + (*bta_av_cb.p_cback)(BTA_AV_SUSPEND_EVT, (tBTA_AV *) &suspend_rsp); + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_str_ok +** +** Description report reconfigure successful +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RECONFIG evt; + UNUSED(p_data); + + p_scb->l2c_cid = AVDT_GetL2CapChannel(p_scb->avdt_handle); + APPL_TRACE_DEBUG("bta_av_rcfg_str_ok: l2c_cid: %d", p_scb->l2c_cid); + + /* rc listen */ + bta_av_st_rc_timer(p_scb, NULL); + utl_freebuf((void **)&p_scb->p_cap); + + /* No need to keep the role bits once reconfig is done. */ + p_scb->role &= ~BTA_AV_ROLE_AD_ACP; + p_scb->role &= ~BTA_AV_ROLE_SUSPEND_OPT; + p_scb->role &= ~BTA_AV_ROLE_START_INT; + + { + /* reconfigure success */ + evt.status = BTA_AV_SUCCESS; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_failed +** +** Description process reconfigure failed +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RECONFIG evt; + + APPL_TRACE_DEBUG("bta_av_rcfg_failed num_recfg: %d, conn_lcb:0x%x", + p_scb->num_recfg, bta_av_cb.conn_lcb); + if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) { + bta_av_cco_close(p_scb, p_data); + /* report failure */ + evt.status = BTA_AV_FAIL_STREAM; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + /* go to closing state */ + bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, NULL); + } else { + /* open failed. try again */ + p_scb->num_recfg++; + if (bta_av_cb.conn_lcb) { + AVDT_DisconnectReq(p_scb->peer_addr, bta_av_dt_cback[p_scb->hdi]); + } else { + bta_av_connect_req(p_scb, NULL); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_connect +** +** Description stream closed. reconnect the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + p_scb->cong = FALSE; + p_scb->num_recfg++; + APPL_TRACE_DEBUG("bta_av_rcfg_connect num_recfg: %d", p_scb->num_recfg); + if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) { + /* let bta_av_rcfg_failed report fail */ + bta_av_rcfg_failed(p_scb, NULL); + } else { + AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]); + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_discntd +** +** Description AVDT disconnected. reconnect the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RECONFIG evt; + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_rcfg_discntd num_recfg: %d", p_scb->num_recfg); + p_scb->num_recfg++; + if (p_scb->num_recfg > BTA_AV_RECONFIG_RETRY) { + /* report failure */ + evt.status = BTA_AV_FAIL_STREAM; + evt.chnl = p_scb->chnl; + evt.hndl = p_scb->hndl; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + /* report close event & go to init state */ + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL); + } else { + AVDT_ConnectReq(p_scb->peer_addr, p_scb->sec_mask, bta_av_dt_cback[p_scb->hdi]); + } +} + +/******************************************************************************* +** +** Function bta_av_suspend_cont +** +** Description received the suspend response. +** continue to reconfigure the stream +** +** Returns void +** +*******************************************************************************/ +void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 err_code = p_data->str_msg.msg.hdr.err_code; + tBTA_AV_RECONFIG evt; + + p_scb->started = FALSE; + p_scb->cong = FALSE; + if (err_code) { + if (AVDT_ERR_CONNECT == err_code) { + /* report failure */ + evt.status = BTA_AV_FAIL; + (*bta_av_cb.p_cback)(BTA_AV_RECONFIG_EVT, (tBTA_AV *)&evt); + bta_av_ssm_execute(p_scb, BTA_AV_STR_DISC_FAIL_EVT, NULL); + } else { + APPL_TRACE_ERROR("suspend rejected, try close"); + /* Disable suspend feature only with explicit rejection(not with timeout) */ + if (err_code != AVDT_ERR_TIMEOUT) { + p_scb->suspend_sup = FALSE; + } + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + + AVDT_CloseReq(p_scb->avdt_handle); + } + } else { + APPL_TRACE_DEBUG("bta_av_suspend_cont calling AVDT_ReconfigReq"); + /* reconfig the stream */ + + AVDT_ReconfigReq(p_scb->avdt_handle, p_scb->p_cap); + p_scb->p_cap->psc_mask = p_scb->cur_psc_mask; + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_cfm +** +** Description if reconfigure is successful, report the event +** otherwise, close the stream. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UINT8 err_code = p_data->str_msg.msg.hdr.err_code; + + /* + APPL_TRACE_DEBUG("bta_av_rcfg_cfm"); + */ + if (err_code) { + APPL_TRACE_ERROR("reconfig rejected, try close"); + /* Disable reconfiguration feature only with explicit rejection(not with timeout) */ + if (err_code != AVDT_ERR_TIMEOUT) { + p_scb->recfg_sup = FALSE; + } + /* started flag is FALSE when reconfigure command is sent */ + /* drop the buffers queued in L2CAP */ + L2CA_FlushChannel (p_scb->l2c_cid, L2CAP_FLUSH_CHANS_ALL); + AVDT_CloseReq(p_scb->avdt_handle); + } else { + /* update the codec info after rcfg cfm */ + memcpy(p_scb->cfg.codec_info, p_data->str_msg.msg.reconfig_cfm.p_cfg->codec_info, AVDT_CODEC_SIZE); + /* take the SSM back to OPEN state */ + bta_av_ssm_execute(p_scb, BTA_AV_STR_OPEN_OK_EVT, NULL); + } +} + +/******************************************************************************* +** +** Function bta_av_rcfg_open +** +** Description AVDT is connected. open the stream with the new configuration +** +** Returns void +** +*******************************************************************************/ +void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_rcfg_open, num_disc_snks = %d", p_scb->num_disc_snks); + + if (p_scb->num_disc_snks == 0) { + /* Need to update call-out module so that it will be ready for discover */ + p_scb->p_cos->stop(p_scb->hndl, p_scb->codec_type); + + /* send avdtp discover request */ + AVDT_DiscoverReq(p_scb->peer_addr, p_scb->sep_info, BTA_AV_NUM_SEPS, bta_av_dt_cback[p_scb->hdi]); + } else { + p_scb->codec_type = p_scb->p_cap->codec_info[BTA_AV_CODEC_TYPE_IDX]; + memcpy(p_scb->cfg.codec_info, p_scb->p_cap->codec_info, AVDT_CODEC_SIZE); + /* we may choose to use a different SEP at reconfig. + * adjust the sep_idx now */ + bta_av_adjust_seps_idx(p_scb, bta_av_get_scb_handle(p_scb, AVDT_TSEP_SRC)); + + /* open the stream with the new config */ + p_scb->sep_info_idx = p_scb->rcfg_idx; + AVDT_OpenReq(p_scb->avdt_handle, p_scb->peer_addr, + p_scb->sep_info[p_scb->sep_info_idx].seid, p_scb->p_cap); + } + +} + +/******************************************************************************* +** +** Function bta_av_security_rej +** +** Description Send an AVDTP security reject. +** +** Returns void +** +*******************************************************************************/ +void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); + + AVDT_SecurityRsp(p_scb->avdt_handle, p_scb->avdt_label, AVDT_ERR_BAD_STATE, + NULL, 0); +} + +/******************************************************************************* +** +** Function bta_av_chk_2nd_start +** +** Description check if this is 2nd stream and if it needs to be started. +** This function needs to be kept very similar to bta_av_chk_start +** +** Returns void +** +*******************************************************************************/ +void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SCB *p_scbi; + int i; + BOOLEAN new_started = FALSE; + UNUSED(p_data); + + if ((p_scb->chnl == BTA_AV_CHNL_AUDIO) && (bta_av_cb.audio_open_cnt >= 2)) { + /* more than one audio channel is connected */ + if (!(p_scb->role & BTA_AV_ROLE_SUSPEND_OPT)) { + /* this channel does not need to be reconfigured. + * if there is other channel streaming, start the stream now */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scbi = bta_av_cb.p_scb[i]; + if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) { + if (!new_started) { + /* start the new stream */ + new_started = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL); + } + /* may need to update the flush timeout of this already started stream */ + if (p_scbi->co_started != bta_av_cb.audio_open_cnt) { + p_scbi->co_started = bta_av_cb.audio_open_cnt; + L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] ); + } + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_open_rc +** +** Description Send a message to main SM to open RC channel. +** +** Returns void +** +*******************************************************************************/ +void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_START start; + + APPL_TRACE_DEBUG("bta_av_open_rc use_rc: %d, wait: x%x role:x%x", p_scb->use_rc, p_scb->wait, p_scb->role); + if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) && (p_scb->q_tag == BTA_AV_Q_TAG_START)) { + /* waiting for role switch for some reason & the timer expires */ + if (!bta_av_link_role_ok(p_scb, A2D_SET_ONE_BIT)) { + APPL_TRACE_ERROR ("failed to start streaming for role management reasons!!"); + bta_sys_stop_timer(&p_scb->timer); + start.chnl = p_scb->chnl; + start.status = BTA_AV_FAIL_ROLE; + start.initiator = TRUE; + start.hndl = p_scb->hndl; + p_scb->wait &= ~BTA_AV_WAIT_ROLE_SW_BITS; + bta_av_cb.rs_idx = 0; + (*bta_av_cb.p_cback)(BTA_AV_START_EVT, (tBTA_AV *) &start); + } else { + /* role switch is done. continue to start streaming */ + bta_av_cb.rs_idx = 0; + p_data->hdr.offset = BTA_AV_RS_OK; + bta_av_start_ok (p_scb, p_data); + } + return; + } + + if (p_scb->use_rc == TRUE || (p_scb->role & BTA_AV_ROLE_AD_ACP) ) { + if (bta_av_cb.disc) { + /* AVRC discover db is in use */ + if (p_scb->rc_handle == BTA_AV_RC_HANDLE_NONE) { + /* AVRC channel is not connected. delay a little bit */ + if ((p_scb->wait & BTA_AV_WAIT_ROLE_SW_BITS) == 0) { + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RC_DISC_TIME_VAL); + } else { + p_scb->wait |= BTA_AV_WAIT_CHECK_RC; + } + } + } else { + /* use main SM for AVRC SDP activities */ + bta_av_rc_disc((UINT8)(p_scb->hdi + 1)); + } + } else { + if (BTA_AV_RC_HANDLE_NONE != p_scb->rc_handle) { + /* the open API said that this handle does not want a RC connection. + * disconnect it now */ + AVRC_Close(p_scb->rc_handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_open_at_inc +** +** Description This function is called if API open is called by application +** while state-machine is at incoming state. +** +** Returns void +** +*******************************************************************************/ +void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_API_OPEN *p_buf; + + memcpy (&(p_scb->open_api), &(p_data->api_open), sizeof(tBTA_AV_API_OPEN)); + + if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) { + p_scb->coll_mask |= BTA_AV_COLL_API_CALLED; + + /* API open will be handled at timeout if SNK did not start signalling. */ + /* API open will be ignored if SNK starts signalling. */ + } else { + /* SNK did not start signalling, API was called N seconds timeout. */ + /* We need to switch to INIT state and start opening connection. */ + p_scb->coll_mask = 0; + bta_av_set_scb_sst_init (p_scb); + + if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL) { + memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN)); + bta_sys_sendmsg(p_buf); + } + } +} + +#endif /* BTA_AV_INCLUDED */ diff --git a/components/bt/bluedroid/bta/av/bta_av_act.c b/components/bt/bluedroid/bta/av/bta_av_act.c new file mode 100644 index 0000000000..e0c7c271dc --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_act.c @@ -0,0 +1,1868 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains action functions for advanced audio/video main state + * machine. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include +#include "bta_av_api.h" +#include "bta_av_int.h" +#include "avdt_api.h" +#include "utl.h" +#include "l2c_api.h" +// #include "osi/include/list.h" +#include "list.h" +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif + +#define LOG_TAG "bt_bta_av" +// #include "osi/include/log.h" +#include "bt_trace.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +/* the timer in milliseconds to wait for open req after setconfig for incoming connections */ +#ifndef BTA_AV_SIG_TIME_VAL +#define BTA_AV_SIG_TIME_VAL 8000 +#endif + +/* In millisec to wait for signalling from SNK when it is initiated from SNK. */ +/* If not, we will start signalling from SRC. */ +#ifndef BTA_AV_ACP_SIG_TIME_VAL +#define BTA_AV_ACP_SIG_TIME_VAL 2000 +#endif + +static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle); + +/******************************************************************************* +** +** Function bta_av_get_rcb_by_shdl +** +** Description find the RCB associated with the given SCB handle. +** +** Returns tBTA_AV_RCB +** +*******************************************************************************/ +tBTA_AV_RCB *bta_av_get_rcb_by_shdl(UINT8 shdl) +{ + tBTA_AV_RCB *p_rcb = NULL; + int i; + + for (i = 0; i < BTA_AV_NUM_RCB; i++) { + if (bta_av_cb.rcb[i].shdl == shdl && bta_av_cb.rcb[i].handle != BTA_AV_RC_HANDLE_NONE) { + p_rcb = &bta_av_cb.rcb[i]; + break; + } + } + return p_rcb; +} +#define BTA_AV_STS_NO_RSP 0xFF /* a number not used by tAVRC_STS */ + +/******************************************************************************* +** +** Function bta_av_del_rc +** +** Description delete the given AVRC handle. +** +** Returns void +** +*******************************************************************************/ +void bta_av_del_rc(tBTA_AV_RCB *p_rcb) +{ + tBTA_AV_SCB *p_scb; + UINT8 rc_handle; /* connected AVRCP handle */ + + p_scb = NULL; + if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) { + if (p_rcb->shdl) { + /* Validate array index*/ + if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) { + p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; + } + if (p_scb) { + APPL_TRACE_DEBUG("bta_av_del_rc shdl:%d, srch:%d rc_handle:%d", p_rcb->shdl, + p_scb->rc_handle, p_rcb->handle); + if (p_scb->rc_handle == p_rcb->handle) { + p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE; + } + /* just in case the RC timer is active + if(bta_av_cb.features & BTA_AV_FEAT_RCCT && p_scb->chnl == BTA_AV_CHNL_AUDIO) */ + bta_sys_stop_timer(&p_scb->timer); + } + } + + APPL_TRACE_EVENT("bta_av_del_rc handle: %d status=0x%x, rc_acp_handle:%d, idx:%d", + p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, bta_av_cb.rc_acp_idx); + rc_handle = p_rcb->handle; + if (!(p_rcb->status & BTA_AV_RC_CONN_MASK) || + ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) ) { + p_rcb->status = 0; + p_rcb->handle = BTA_AV_RC_HANDLE_NONE; + p_rcb->shdl = 0; + p_rcb->lidx = 0; + } + /* else ACP && connected. do not clear the handle yet */ + AVRC_Close(rc_handle); + if (rc_handle == bta_av_cb.rc_acp_handle) { + bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE; + } + APPL_TRACE_EVENT("end del_rc handle: %d status=0x%x, rc_acp_handle:%d, lidx:%d", + p_rcb->handle, p_rcb->status, bta_av_cb.rc_acp_handle, p_rcb->lidx); + } +} + + +/******************************************************************************* +** +** Function bta_av_close_all_rc +** +** Description close the all AVRC handle. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_close_all_rc(tBTA_AV_CB *p_cb) +{ + int i; + + for (i = 0; i < BTA_AV_NUM_RCB; i++) { + if ((p_cb->disabling == TRUE) || (bta_av_cb.rcb[i].shdl != 0)) { + bta_av_del_rc(&bta_av_cb.rcb[i]); + } + } +} + +/******************************************************************************* +** +** Function bta_av_del_sdp_rec +** +** Description delete the given SDP record handle. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_del_sdp_rec(UINT32 *p_sdp_handle) +{ + if (*p_sdp_handle != 0) { + SDP_DeleteRecord(*p_sdp_handle); + *p_sdp_handle = 0; + } +} + +/******************************************************************************* +** +** Function bta_av_avrc_sdp_cback +** +** Description AVRCP service discovery callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_avrc_sdp_cback(UINT16 status) +{ + BT_HDR *p_msg; + UNUSED(status); + + if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_msg->event = BTA_AV_SDP_AVRC_DISC_EVT; + bta_sys_sendmsg(p_msg); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_ctrl_cback +** +** Description AVRCP control callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_rc_ctrl_cback(UINT8 handle, UINT8 event, UINT16 result, BD_ADDR peer_addr) +{ + tBTA_AV_RC_CONN_CHG *p_msg; + UINT16 msg_event = 0; + UNUSED(result); + +#if (defined(BTA_AV_MIN_DEBUG_TRACES) && BTA_AV_MIN_DEBUG_TRACES == TRUE) + APPL_TRACE_EVENT("rc_ctrl handle: %d event=0x%x", handle, event); +#else + APPL_TRACE_EVENT("bta_av_rc_ctrl_cback handle: %d event=0x%x", handle, event); +#endif + if (event == AVRC_OPEN_IND_EVT) { + /* save handle of opened connection + bta_av_cb.rc_handle = handle;*/ + + msg_event = BTA_AV_AVRC_OPEN_EVT; + } else if (event == AVRC_CLOSE_IND_EVT) { + msg_event = BTA_AV_AVRC_CLOSE_EVT; + } + + if (msg_event) { + if ((p_msg = (tBTA_AV_RC_CONN_CHG *) GKI_getbuf(sizeof(tBTA_AV_RC_CONN_CHG))) != NULL) { + p_msg->hdr.event = msg_event; + p_msg->handle = handle; + if (peer_addr) { + bdcpy(p_msg->peer_addr, peer_addr); + } + bta_sys_sendmsg(p_msg); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_msg_cback +** +** Description AVRCP message callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_rc_msg_cback(UINT8 handle, UINT8 label, UINT8 opcode, tAVRC_MSG *p_msg) +{ + UINT8 *p_data_src = NULL; + UINT16 data_len = 0; + + APPL_TRACE_DEBUG("%s handle: %u opcode=0x%x", __func__, handle, opcode); + + /* Determine the size of the buffer we need */ + if (opcode == AVRC_OP_VENDOR && p_msg->vendor.p_vendor_data != NULL) { + p_data_src = p_msg->vendor.p_vendor_data; + data_len = (UINT16) p_msg->vendor.vendor_len; + } else if (opcode == AVRC_OP_PASS_THRU && p_msg->pass.p_pass_data != NULL) { + p_data_src = p_msg->pass.p_pass_data; + data_len = (UINT16) p_msg->pass.pass_len; + } + + /* Create a copy of the message */ + tBTA_AV_RC_MSG *p_buf = + (tBTA_AV_RC_MSG *)GKI_getbuf((UINT16)(sizeof(tBTA_AV_RC_MSG) + data_len)); + if (p_buf != NULL) { + p_buf->hdr.event = BTA_AV_AVRC_MSG_EVT; + p_buf->handle = handle; + p_buf->label = label; + p_buf->opcode = opcode; + memcpy(&p_buf->msg, p_msg, sizeof(tAVRC_MSG)); + /* Copy the data payload, and set the pointer to it */ + if (p_data_src != NULL) { + UINT8 *p_data_dst = (UINT8 *)(p_buf + 1); + memcpy(p_data_dst, p_data_src, data_len); + if (opcode == AVRC_OP_VENDOR) { + p_buf->msg.vendor.p_vendor_data = p_data_dst; + } else if (opcode == AVRC_OP_PASS_THRU) { + p_buf->msg.pass.p_pass_data = p_data_dst; + } + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_create +** +** Description alloc RCB and call AVRC_Open +** +** Returns the created rc handle +** +*******************************************************************************/ +UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx) +{ + tAVRC_CONN_CB ccb; + BD_ADDR_PTR bda = (BD_ADDR_PTR)bd_addr_any; + UINT8 status = BTA_AV_RC_ROLE_ACP; + tBTA_AV_SCB *p_scb = p_cb->p_scb[shdl - 1]; + int i; + UINT8 rc_handle; + tBTA_AV_RCB *p_rcb; + + if (role == AVCT_INT) { + bda = p_scb->peer_addr; + status = BTA_AV_RC_ROLE_INT; + } else { + if ((p_rcb = bta_av_get_rcb_by_shdl(shdl)) != NULL ) { + APPL_TRACE_ERROR("bta_av_rc_create ACP handle exist for shdl:%d", shdl); + return p_rcb->handle; + } + } + + ccb.p_ctrl_cback = bta_av_rc_ctrl_cback; + ccb.p_msg_cback = bta_av_rc_msg_cback; + ccb.company_id = p_bta_av_cfg->company_id; + ccb.conn = role; + /* note: BTA_AV_FEAT_RCTG = AVRC_CT_TARGET, BTA_AV_FEAT_RCCT = AVRC_CT_CONTROL */ + ccb.control = p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_RCCT | AVRC_CT_PASSIVE); + + + if (AVRC_Open(&rc_handle, &ccb, bda) != AVRC_SUCCESS) { + return BTA_AV_RC_HANDLE_NONE; + } + + i = rc_handle; + p_rcb = &p_cb->rcb[i]; + + if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) { + APPL_TRACE_ERROR("bta_av_rc_create found duplicated handle:%d", rc_handle); + } + + p_rcb->handle = rc_handle; + p_rcb->status = status; + p_rcb->shdl = shdl; + p_rcb->lidx = lidx; + p_rcb->peer_features = 0; + if (lidx == (BTA_AV_NUM_LINKS + 1)) { + /* this LIDX is reserved for the AVRCP ACP connection */ + p_cb->rc_acp_handle = p_rcb->handle; + p_cb->rc_acp_idx = (i + 1); + APPL_TRACE_DEBUG("rc_acp_handle:%d idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx); + } + APPL_TRACE_DEBUG("create %d, role: %d, shdl:%d, rc_handle:%d, lidx:%d, status:0x%x", + i, role, shdl, p_rcb->handle, lidx, p_rcb->status); + + return rc_handle; +} + +/******************************************************************************* +** +** Function bta_av_valid_group_navi_msg +** +** Description Check if it is Group Navigation Msg for Metadata +** +** Returns BTA_AV_RSP_ACCEPT or BTA_AV_RSP_NOT_IMPL. +** +*******************************************************************************/ +static tBTA_AV_CODE bta_av_group_navi_supported(UINT8 len, UINT8 *p_data, BOOLEAN is_inquiry) +{ + tBTA_AV_CODE ret = BTA_AV_RSP_NOT_IMPL; + UINT8 *p_ptr = p_data; + UINT16 u16; + UINT32 u32; + + if (p_bta_av_cfg->avrc_group && len == BTA_GROUP_NAVI_MSG_OP_DATA_LEN) { + BTA_AV_BE_STREAM_TO_CO_ID(u32, p_ptr); + BE_STREAM_TO_UINT16(u16, p_ptr); + + if (u32 == AVRC_CO_METADATA) { + if (is_inquiry) { + if (u16 <= AVRC_PDU_PREV_GROUP) { + ret = BTA_AV_RSP_IMPL_STBL; + } + } else { + if (u16 <= AVRC_PDU_PREV_GROUP) { + ret = BTA_AV_RSP_ACCEPT; + } else { + ret = BTA_AV_RSP_REJ; + } + } + } + } + + return ret; +} + +/******************************************************************************* +** +** Function bta_av_op_supported +** +** Description Check if remote control operation is supported. +** +** Returns BTA_AV_RSP_ACCEPT of supported, BTA_AV_RSP_NOT_IMPL if not. +** +*******************************************************************************/ +static tBTA_AV_CODE bta_av_op_supported(tBTA_AV_RC rc_id, BOOLEAN is_inquiry) +{ + tBTA_AV_CODE ret_code = BTA_AV_RSP_NOT_IMPL; + + if (p_bta_av_rc_id) { + if (is_inquiry) { + if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) { + ret_code = BTA_AV_RSP_IMPL_STBL; + } + } else { + if (p_bta_av_rc_id[rc_id >> 4] & (1 << (rc_id & 0x0F))) { + ret_code = BTA_AV_RSP_ACCEPT; + } else if ((p_bta_av_cfg->rc_pass_rsp == BTA_AV_RSP_INTERIM) && p_bta_av_rc_id_ac) { + if (p_bta_av_rc_id_ac[rc_id >> 4] & (1 << (rc_id & 0x0F))) { + ret_code = BTA_AV_RSP_INTERIM; + } + } + } + + } + return ret_code; +} + +/******************************************************************************* +** +** Function bta_av_find_lcb +** +** Description Given BD_addr, find the associated LCB. +** +** Returns NULL, if not found. +** +*******************************************************************************/ +tBTA_AV_LCB *bta_av_find_lcb(BD_ADDR addr, UINT8 op) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + int xx; + UINT8 mask; + tBTA_AV_LCB *p_lcb = NULL; + + for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) { + mask = 1 << xx; /* the used mask for this lcb */ + if ((mask & p_cb->conn_lcb) && 0 == ( bdcmp(p_cb->lcb[xx].addr, addr))) { + p_lcb = &p_cb->lcb[xx]; + if (op == BTA_AV_LCB_FREE) { + p_cb->conn_lcb &= ~mask; /* clear the connect mask */ + APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb); + } + break; + } + } + return p_lcb; +} + +/******************************************************************************* +** +** Function bta_av_rc_opened +** +** Description Set AVRCP state to opened. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_opened(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RC_OPEN rc_open; + tBTA_AV_SCB *p_scb; + int i; + UINT8 shdl = 0; + tBTA_AV_LCB *p_lcb; + tBTA_AV_RCB *p_rcb; + UINT8 tmp; + UINT8 disc = 0; + + /* find the SCB & stop the timer */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scb = p_cb->p_scb[i]; + if (p_scb && bdcmp(p_scb->peer_addr, p_data->rc_conn_chg.peer_addr) == 0) { + p_scb->rc_handle = p_data->rc_conn_chg.handle; + APPL_TRACE_DEBUG("bta_av_rc_opened shdl:%d, srch %d", i + 1, p_scb->rc_handle); + shdl = i + 1; + LOG_INFO("%s allow incoming AVRCP connections:%d", __func__, p_scb->use_rc); + bta_sys_stop_timer(&p_scb->timer); + disc = p_scb->hndl; + break; + } + } + + i = p_data->rc_conn_chg.handle; + if (p_cb->rcb[i].handle == BTA_AV_RC_HANDLE_NONE) { + APPL_TRACE_ERROR("not a valid handle:%d any more", i); + return; + } + + + if (p_cb->rcb[i].lidx == (BTA_AV_NUM_LINKS + 1) && shdl != 0) { + /* rc is opened on the RC only ACP channel, but is for a specific + * SCB -> need to switch RCBs */ + p_rcb = bta_av_get_rcb_by_shdl(shdl); + if (p_rcb) { + p_rcb->shdl = p_cb->rcb[i].shdl; + tmp = p_rcb->lidx; + p_rcb->lidx = p_cb->rcb[i].lidx; + p_cb->rcb[i].lidx = tmp; + p_cb->rc_acp_handle = p_rcb->handle; + p_cb->rc_acp_idx = (p_rcb - p_cb->rcb) + 1; + APPL_TRACE_DEBUG("switching RCB rc_acp_handle:%d idx:%d", + p_cb->rc_acp_handle, p_cb->rc_acp_idx); + } + } + + p_cb->rcb[i].shdl = shdl; + rc_open.rc_handle = i; + APPL_TRACE_ERROR("bta_av_rc_opened rcb[%d] shdl:%d lidx:%d/%d", + i, shdl, p_cb->rcb[i].lidx, p_cb->lcb[BTA_AV_NUM_LINKS].lidx); + p_cb->rcb[i].status |= BTA_AV_RC_CONN_MASK; + + if (!shdl && 0 == p_cb->lcb[BTA_AV_NUM_LINKS].lidx) { + /* no associated SCB -> connected to an RC only device + * update the index to the extra LCB */ + p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS]; + bdcpy(p_lcb->addr, p_data->rc_conn_chg.peer_addr); + APPL_TRACE_DEBUG("rc_only bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + p_lcb->addr[0], p_lcb->addr[1], + p_lcb->addr[2], p_lcb->addr[3], + p_lcb->addr[4], p_lcb->addr[5]); + p_lcb->lidx = BTA_AV_NUM_LINKS + 1; + p_cb->rcb[i].lidx = p_lcb->lidx; + p_lcb->conn_msk = 1; + APPL_TRACE_ERROR("rcb[%d].lidx=%d, lcb.conn_msk=x%x", + i, p_cb->rcb[i].lidx, p_lcb->conn_msk); + disc = p_data->rc_conn_chg.handle | BTA_AV_CHNL_MSK; + } + + bdcpy(rc_open.peer_addr, p_data->rc_conn_chg.peer_addr); + rc_open.peer_features = p_cb->rcb[i].peer_features; + rc_open.status = BTA_AV_SUCCESS; + APPL_TRACE_DEBUG("local features:x%x peer_features:x%x", p_cb->features, + rc_open.peer_features); + if (rc_open.peer_features == 0) { + /* we have not done SDP on peer RC capabilities. + * peer must have initiated the RC connection */ + rc_open.peer_features = BTA_AV_FEAT_RCCT; + bta_av_rc_disc(disc); + } + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open); + +} + + +/******************************************************************************* +** +** Function bta_av_rc_remote_cmd +** +** Description Send an AVRCP remote control command. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_remote_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + if (p_cb->features & BTA_AV_FEAT_RCCT) { + if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + if (p_rcb->status & BTA_AV_RC_CONN_MASK) { + AVRC_PassCmd(p_rcb->handle, p_data->api_remote_cmd.label, + &p_data->api_remote_cmd.msg); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_vendor_cmd +** +** Description Send an AVRCP vendor specific command. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_vendor_cmd(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + if ( (p_cb->features & (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) == + (BTA_AV_FEAT_RCCT | BTA_AV_FEAT_VENDOR)) { + if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + AVRC_VendorCmd(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_vendor_rsp +** +** Description Send an AVRCP vendor specific response. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_vendor_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + if ( (p_cb->features & (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) == + (BTA_AV_FEAT_RCTG | BTA_AV_FEAT_VENDOR)) { + if (p_data->hdr.layer_specific < BTA_AV_NUM_RCB) { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + AVRC_VendorRsp(p_rcb->handle, p_data->api_vendor.label, &p_data->api_vendor.msg); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rc_meta_rsp +** +** Description Send an AVRCP metadata/advanced control command/response. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_meta_rsp(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_RCB *p_rcb; + BOOLEAN do_free = TRUE; + + if ((p_cb->features & BTA_AV_FEAT_METADATA) && (p_data->hdr.layer_specific < BTA_AV_NUM_RCB)) { + if ((p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCTG)) || + (!p_data->api_meta_rsp.is_rsp && (p_cb->features & BTA_AV_FEAT_RCCT)) ) { + p_rcb = &p_cb->rcb[p_data->hdr.layer_specific]; + if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) { + AVRC_MsgReq(p_rcb->handle, p_data->api_meta_rsp.label, + p_data->api_meta_rsp.rsp_code, + p_data->api_meta_rsp.p_pkt); + do_free = FALSE; + } + } + } + + if (do_free) { + GKI_freebuf (p_data->api_meta_rsp.p_pkt); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_free_rsp +** +** Description free an AVRCP metadata command buffer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_cb); + + GKI_freebuf (p_data->api_meta_rsp.p_pkt); +} + +/******************************************************************************* +** +** Function bta_av_rc_meta_req +** +** Description Send an AVRCP metadata command. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + UNUSED(p_cb); + UNUSED(p_data); +} + + + +/******************************************************************************* +** +** Function bta_av_chk_notif_evt_id +** +** Description make sure the requested player id is valid. +** +** Returns BTA_AV_STS_NO_RSP, if no error +** +*******************************************************************************/ +static tAVRC_STS bta_av_chk_notif_evt_id(tAVRC_MSG_VENDOR *p_vendor) +{ + tAVRC_STS status = BTA_AV_STS_NO_RSP; + UINT8 xx; + UINT16 u16; + UINT8 *p = p_vendor->p_vendor_data + 2; + + BE_STREAM_TO_UINT16 (u16, p); + /* double check the fixed length */ + if ((u16 != 5) || (p_vendor->vendor_len != 9)) { + status = AVRC_STS_INTERNAL_ERR; + } else { + /* make sure the player_id is valid */ + for (xx = 0; xx < p_bta_av_cfg->num_evt_ids; xx++) { + if (*p == p_bta_av_cfg->p_meta_evt_ids[xx]) { + break; + } + } + if (xx == p_bta_av_cfg->num_evt_ids) { + status = AVRC_STS_BAD_PARAM; + } + } + + return status; +} + +/******************************************************************************* +** +** Function bta_av_proc_meta_cmd +** +** Description Process an AVRCP metadata command from the peer. +** +** Returns TRUE to respond immediately +** +*******************************************************************************/ +tBTA_AV_EVT bta_av_proc_meta_cmd(tAVRC_RESPONSE *p_rc_rsp, tBTA_AV_RC_MSG *p_msg, UINT8 *p_ctype) +{ + tBTA_AV_EVT evt = BTA_AV_META_MSG_EVT; + UINT8 u8, pdu, *p; + UINT16 u16; + tAVRC_MSG_VENDOR *p_vendor = &p_msg->msg.vendor; + +#if (AVRC_METADATA_INCLUDED == TRUE) + + pdu = *(p_vendor->p_vendor_data); + p_rc_rsp->pdu = pdu; + *p_ctype = AVRC_RSP_REJ; + /* Metadata messages only use PANEL sub-unit type */ + if (p_vendor->hdr.subunit_type != AVRC_SUB_PANEL) { + APPL_TRACE_DEBUG("SUBUNIT must be PANEL"); + /* reject it */ + evt = 0; + p_vendor->hdr.ctype = BTA_AV_RSP_NOT_IMPL; + AVRC_VendorRsp(p_msg->handle, p_msg->label, &p_msg->msg.vendor); + } else if (!AVRC_IsValidAvcType(pdu, p_vendor->hdr.ctype) ) { + APPL_TRACE_DEBUG("Invalid pdu/ctype: 0x%x, %d", pdu, p_vendor->hdr.ctype); + /* reject invalid message without reporting to app */ + evt = 0; + p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD; + } else { + switch (pdu) { + case AVRC_PDU_GET_CAPABILITIES: + /* process GetCapabilities command without reporting the event to app */ + evt = 0; + u8 = *(p_vendor->p_vendor_data + 4); + p = p_vendor->p_vendor_data + 2; + p_rc_rsp->get_caps.capability_id = u8; + BE_STREAM_TO_UINT16 (u16, p); + if ((u16 != 1) || (p_vendor->vendor_len != 5)) { + p_rc_rsp->get_caps.status = AVRC_STS_INTERNAL_ERR; + } else { + p_rc_rsp->get_caps.status = AVRC_STS_NO_ERROR; + if (u8 == AVRC_CAP_COMPANY_ID) { + *p_ctype = AVRC_RSP_IMPL_STBL; + p_rc_rsp->get_caps.count = p_bta_av_cfg->num_co_ids; + memcpy(p_rc_rsp->get_caps.param.company_id, p_bta_av_cfg->p_meta_co_ids, + (p_bta_av_cfg->num_co_ids << 2)); + } else if (u8 == AVRC_CAP_EVENTS_SUPPORTED) { + *p_ctype = AVRC_RSP_IMPL_STBL; + p_rc_rsp->get_caps.count = p_bta_av_cfg->num_evt_ids; + memcpy(p_rc_rsp->get_caps.param.event_id, p_bta_av_cfg->p_meta_evt_ids, + p_bta_av_cfg->num_evt_ids); + } else { + APPL_TRACE_DEBUG("Invalid capability ID: 0x%x", u8); + /* reject - unknown capability ID */ + p_rc_rsp->get_caps.status = AVRC_STS_BAD_PARAM; + } + } + break; + + + case AVRC_PDU_REGISTER_NOTIFICATION: + /* make sure the event_id is implemented */ + p_rc_rsp->rsp.status = bta_av_chk_notif_evt_id (p_vendor); + if (p_rc_rsp->rsp.status != BTA_AV_STS_NO_RSP) { + evt = 0; + } + break; + + } + } +#else + APPL_TRACE_DEBUG("AVRCP 1.3 Metadata not supporteed. Reject command."); + /* reject invalid message without reporting to app */ + evt = 0; + p_rc_rsp->rsp.status = AVRC_STS_BAD_CMD; +#endif + + return evt; +} + + +/******************************************************************************* +** +** Function bta_av_rc_msg +** +** Description Process an AVRCP message from the peer. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_msg(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + tBTA_AV_EVT evt = 0; + tBTA_AV av; + BT_HDR *p_pkt = NULL; + tAVRC_MSG_VENDOR *p_vendor = &p_data->rc_msg.msg.vendor; + BOOLEAN is_inquiry = ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) || p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ); +#if (AVRC_METADATA_INCLUDED == TRUE) + UINT8 ctype = 0; + tAVRC_RESPONSE rc_rsp; + + rc_rsp.rsp.status = BTA_AV_STS_NO_RSP; +#endif + + if (p_data->rc_msg.opcode == AVRC_OP_PASS_THRU) { + /* if this is a pass thru command */ + if ((p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_CTRL) || + (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_SPEC_INQ) || + (p_data->rc_msg.msg.hdr.ctype == AVRC_CMD_GEN_INQ) + ) { + /* check if operation is supported */ + if (p_data->rc_msg.msg.pass.op_id == AVRC_ID_VENDOR) { + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL; +#if (AVRC_METADATA_INCLUDED == TRUE) + if (p_cb->features & BTA_AV_FEAT_METADATA) + p_data->rc_msg.msg.hdr.ctype = + bta_av_group_navi_supported(p_data->rc_msg.msg.pass.pass_len, + p_data->rc_msg.msg.pass.p_pass_data, is_inquiry); +#endif + } else { + p_data->rc_msg.msg.hdr.ctype = bta_av_op_supported(p_data->rc_msg.msg.pass.op_id, is_inquiry); + } + + APPL_TRACE_DEBUG("ctype %d", p_data->rc_msg.msg.hdr.ctype) + + /* send response */ + if (p_data->rc_msg.msg.hdr.ctype != BTA_AV_RSP_INTERIM) { + AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass); + } + + /* set up for callback if supported */ + if (p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_ACCEPT || p_data->rc_msg.msg.hdr.ctype == BTA_AV_RSP_INTERIM) { + evt = BTA_AV_REMOTE_CMD_EVT; + av.remote_cmd.rc_id = p_data->rc_msg.msg.pass.op_id; + av.remote_cmd.key_state = p_data->rc_msg.msg.pass.state; + av.remote_cmd.p_data = p_data->rc_msg.msg.pass.p_pass_data; + av.remote_cmd.len = p_data->rc_msg.msg.pass.pass_len; + memcpy(&av.remote_cmd.hdr, &p_data->rc_msg.msg.hdr, sizeof (tAVRC_HDR)); + av.remote_cmd.label = p_data->rc_msg.label; + } + } + /* else if this is a pass thru response */ + else if (p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT) { + /* set up for callback */ + evt = BTA_AV_REMOTE_RSP_EVT; + av.remote_rsp.rc_id = p_data->rc_msg.msg.pass.op_id; + av.remote_rsp.key_state = p_data->rc_msg.msg.pass.state; + av.remote_rsp.rsp_code = p_data->rc_msg.msg.hdr.ctype; + av.remote_rsp.label = p_data->rc_msg.label; + } + /* must be a bad ctype -> reject*/ + else { + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ; + AVRC_PassRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.pass); + } + } + /* else if this is a vendor specific command or response */ + else if (p_data->rc_msg.opcode == AVRC_OP_VENDOR) { + /* set up for callback */ + av.vendor_cmd.code = p_data->rc_msg.msg.hdr.ctype; + av.vendor_cmd.company_id = p_vendor->company_id; + av.vendor_cmd.label = p_data->rc_msg.label; + av.vendor_cmd.p_data = p_vendor->p_vendor_data; + av.vendor_cmd.len = p_vendor->vendor_len; + + /* if configured to support vendor specific and it's a command */ + if ((p_cb->features & BTA_AV_FEAT_VENDOR) && + p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) { +#if (AVRC_METADATA_INCLUDED == TRUE) + if ((p_cb->features & BTA_AV_FEAT_METADATA) && + (p_vendor->company_id == AVRC_CO_METADATA)) { + av.meta_msg.p_msg = &p_data->rc_msg.msg; + evt = bta_av_proc_meta_cmd (&rc_rsp, &p_data->rc_msg, &ctype); + } else +#endif + evt = BTA_AV_VENDOR_CMD_EVT; + } + /* else if configured to support vendor specific and it's a response */ + else if ((p_cb->features & BTA_AV_FEAT_VENDOR) && + p_data->rc_msg.msg.hdr.ctype >= AVRC_RSP_ACCEPT) { +#if (AVRC_METADATA_INCLUDED == TRUE) + if ((p_cb->features & BTA_AV_FEAT_METADATA) && + (p_vendor->company_id == AVRC_CO_METADATA)) { + av.meta_msg.p_msg = &p_data->rc_msg.msg; + evt = BTA_AV_META_MSG_EVT; + } else +#endif + evt = BTA_AV_VENDOR_RSP_EVT; + + } + /* else if not configured to support vendor specific and it's a command */ + else if (!(p_cb->features & BTA_AV_FEAT_VENDOR) && + p_data->rc_msg.msg.hdr.ctype <= AVRC_CMD_GEN_INQ) { + if (p_data->rc_msg.msg.vendor.p_vendor_data[0] == AVRC_PDU_INVALID) { + /* reject it */ + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_REJ; + p_data->rc_msg.msg.vendor.p_vendor_data[4] = AVRC_STS_BAD_CMD; + } else { + p_data->rc_msg.msg.hdr.ctype = BTA_AV_RSP_NOT_IMPL; + } + AVRC_VendorRsp(p_data->rc_msg.handle, p_data->rc_msg.label, &p_data->rc_msg.msg.vendor); + } + } +#if (AVRC_METADATA_INCLUDED == TRUE) + if (evt == 0 && rc_rsp.rsp.status != BTA_AV_STS_NO_RSP) { + if (!p_pkt) { + rc_rsp.rsp.opcode = p_data->rc_msg.opcode; + AVRC_BldResponse (0, &rc_rsp, &p_pkt); + } + if (p_pkt) { + AVRC_MsgReq (p_data->rc_msg.handle, p_data->rc_msg.label, ctype, p_pkt); + } + } +#endif + + /* call callback */ + if (evt != 0) { + av.remote_cmd.rc_handle = p_data->rc_msg.handle; + (*p_cb->p_cback)(evt, &av); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_close +** +** Description close the specified AVRC handle. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + UINT16 handle = p_data->hdr.layer_specific; + tBTA_AV_SCB *p_scb; + tBTA_AV_RCB *p_rcb; + + if (handle < BTA_AV_NUM_RCB) { + p_rcb = &p_cb->rcb[handle]; + + APPL_TRACE_DEBUG("bta_av_rc_close handle: %d, status=0x%x", p_rcb->handle, p_rcb->status); + if (p_rcb->handle != BTA_AV_RC_HANDLE_NONE) { + if (p_rcb->shdl) { + p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; + if (p_scb) { + /* just in case the RC timer is active + if(bta_av_cb.features & BTA_AV_FEAT_RCCT && + p_scb->chnl == BTA_AV_CHNL_AUDIO) */ + bta_sys_stop_timer(&p_scb->timer); + } + } + + AVRC_Close(p_rcb->handle); + } + } +} + +/******************************************************************************* +** +** Function bta_av_get_shdl +** +** Returns The index to p_scb[] +** +*******************************************************************************/ +static UINT8 bta_av_get_shdl(tBTA_AV_SCB *p_scb) +{ + int i; + UINT8 shdl = 0; + /* find the SCB & stop the timer */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + if (p_scb == bta_av_cb.p_scb[i]) { + shdl = i + 1; + break; + } + } + return shdl; +} + +/******************************************************************************* +** +** Function bta_av_stream_chg +** +** Description audio streaming status changed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_stream_chg(tBTA_AV_SCB *p_scb, BOOLEAN started) +{ + UINT8 started_msk; + int i; + UINT8 *p_streams; + BOOLEAN no_streams = FALSE; + tBTA_AV_SCB *p_scbi; + + started_msk = BTA_AV_HNDL_TO_MSK(p_scb->hdi); + APPL_TRACE_DEBUG ("bta_av_stream_chg started:%d started_msk:x%x chnl:x%x", started, + started_msk, p_scb->chnl); + if (BTA_AV_CHNL_AUDIO == p_scb->chnl) { + p_streams = &bta_av_cb.audio_streams; + } else { + p_streams = &bta_av_cb.video_streams; + } + + if (started) { + /* Let L2CAP know this channel is processed with high priority */ + L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_HIGH); + (*p_streams) |= started_msk; + } else { + (*p_streams) &= ~started_msk; + } + + if (!started) { + i = 0; + if (BTA_AV_CHNL_AUDIO == p_scb->chnl) { + if (bta_av_cb.video_streams == 0) { + no_streams = TRUE; + } + } else { + no_streams = TRUE; + if ( bta_av_cb.audio_streams ) { + for (; i < BTA_AV_NUM_STRS; i++) { + p_scbi = bta_av_cb.p_scb[i]; + /* scb is used and started */ + if ( p_scbi && (bta_av_cb.audio_streams & BTA_AV_HNDL_TO_MSK(i)) + && bdcmp(p_scbi->peer_addr, p_scb->peer_addr) == 0) { + no_streams = FALSE; + break; + } + } + + } + } + + APPL_TRACE_DEBUG ("no_streams:%d i:%d, audio_streams:x%x, video_streams:x%x", no_streams, i, + bta_av_cb.audio_streams, bta_av_cb.video_streams); + if (no_streams) { + /* Let L2CAP know this channel is processed with low priority */ + L2CA_SetAclPriority(p_scb->peer_addr, L2CAP_PRIORITY_NORMAL); + } + } +} + + +/******************************************************************************* +** +** Function bta_av_conn_chg +** +** Description connetion status changed. +** Open an AVRCP acceptor channel, if new conn. +** +** Returns void +** +*******************************************************************************/ +void bta_av_conn_chg(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb = NULL; + tBTA_AV_SCB *p_scbi; + UINT8 mask; + UINT8 conn_msk; + UINT8 old_msk; + int i; + int index = (p_data->hdr.layer_specific & BTA_AV_HNDL_MSK) - 1; + tBTA_AV_LCB *p_lcb; + tBTA_AV_LCB *p_lcb_rc; + tBTA_AV_RCB *p_rcb, *p_rcb2; + BOOLEAN chk_restore = FALSE; + + /* Validate array index*/ + if (index < BTA_AV_NUM_STRS) { + p_scb = p_cb->p_scb[index]; + } + mask = BTA_AV_HNDL_TO_MSK(index); + p_lcb = bta_av_find_lcb(p_data->conn_chg.peer_addr, BTA_AV_LCB_FIND); + conn_msk = 1 << (index + 1); + if (p_data->conn_chg.is_up) { + /* set the conned mask for this channel */ + if (p_scb) { + if (p_lcb) { + p_lcb->conn_msk |= conn_msk; + for (i = 0; i < BTA_AV_NUM_RCB; i++) { + if (bta_av_cb.rcb[i].lidx == p_lcb->lidx) { + bta_av_cb.rcb[i].shdl = index + 1; + APPL_TRACE_DEBUG("conn_chg up[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i, + bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, + bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx); + break; + } + } + } + if (p_scb->chnl == BTA_AV_CHNL_AUDIO) { + old_msk = p_cb->conn_audio; + p_cb->conn_audio |= mask; + } else { + old_msk = p_cb->conn_video; + p_cb->conn_video |= mask; + } + + if ((old_msk & mask) == 0) { + /* increase the audio open count, if not set yet */ + bta_av_cb.audio_open_cnt++; + } + + + APPL_TRACE_DEBUG("rc_acp_handle:%d rc_acp_idx:%d", p_cb->rc_acp_handle, p_cb->rc_acp_idx); + /* check if the AVRCP ACP channel is already connected */ + if (p_lcb && p_cb->rc_acp_handle != BTA_AV_RC_HANDLE_NONE && p_cb->rc_acp_idx) { + p_lcb_rc = &p_cb->lcb[BTA_AV_NUM_LINKS]; + APPL_TRACE_DEBUG("rc_acp is connected && conn_chg on same addr p_lcb_rc->conn_msk:x%x", + p_lcb_rc->conn_msk); + /* check if the RC is connected to the scb addr */ + APPL_TRACE_DEBUG ("p_lcb_rc->addr: %02x:%02x:%02x:%02x:%02x:%02x", + p_lcb_rc->addr[0], p_lcb_rc->addr[1], p_lcb_rc->addr[2], p_lcb_rc->addr[3], + p_lcb_rc->addr[4], p_lcb_rc->addr[5]); + APPL_TRACE_DEBUG ("conn_chg.peer_addr: %02x:%02x:%02x:%02x:%02x:%02x", + p_data->conn_chg.peer_addr[0], p_data->conn_chg.peer_addr[1], + p_data->conn_chg.peer_addr[2], + p_data->conn_chg.peer_addr[3], p_data->conn_chg.peer_addr[4], + p_data->conn_chg.peer_addr[5]); + if (p_lcb_rc->conn_msk && bdcmp(p_lcb_rc->addr, p_data->conn_chg.peer_addr) == 0) { + /* AVRCP is already connected. + * need to update the association betwen SCB and RCB */ + p_lcb_rc->conn_msk = 0; /* indicate RC ONLY is not connected */ + p_lcb_rc->lidx = 0; + p_scb->rc_handle = p_cb->rc_acp_handle; + p_rcb = &p_cb->rcb[p_cb->rc_acp_idx - 1]; + p_rcb->shdl = bta_av_get_shdl(p_scb); + APPL_TRACE_DEBUG("update rc_acp shdl:%d/%d srch:%d", index + 1, p_rcb->shdl, + p_scb->rc_handle ); + + p_rcb2 = bta_av_get_rcb_by_shdl(p_rcb->shdl); + if (p_rcb2) { + /* found the RCB that was created to associated with this SCB */ + p_cb->rc_acp_handle = p_rcb2->handle; + p_cb->rc_acp_idx = (p_rcb2 - p_cb->rcb) + 1; + APPL_TRACE_DEBUG("new rc_acp_handle:%d, idx:%d", p_cb->rc_acp_handle, + p_cb->rc_acp_idx); + p_rcb2->lidx = (BTA_AV_NUM_LINKS + 1); + APPL_TRACE_DEBUG("rc2 handle:%d lidx:%d/%d", p_rcb2->handle, p_rcb2->lidx, + p_cb->lcb[p_rcb2->lidx - 1].lidx); + } + p_rcb->lidx = p_lcb->lidx; + APPL_TRACE_DEBUG("rc handle:%d lidx:%d/%d", p_rcb->handle, p_rcb->lidx, + p_cb->lcb[p_rcb->lidx - 1].lidx); + } + } + } + } else { + if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) { + /* this channel is still marked as open. decrease the count */ + bta_av_cb.audio_open_cnt--; + } + + /* clear the conned mask for this channel */ + p_cb->conn_audio &= ~mask; + p_cb->conn_video &= ~mask; + if (p_scb) { + /* the stream is closed. + * clear the peer address, so it would not mess up the AVRCP for the next round of operation */ + bdcpy(p_scb->peer_addr, bd_addr_null); + if (p_scb->chnl == BTA_AV_CHNL_AUDIO) { + if (p_lcb) { + p_lcb->conn_msk &= ~conn_msk; + } + /* audio channel is down. make sure the INT channel is down */ + /* just in case the RC timer is active + if(p_cb->features & BTA_AV_FEAT_RCCT) */ + { + bta_sys_stop_timer(&p_scb->timer); + } + /* one audio channel goes down. check if we need to restore high priority */ + chk_restore = TRUE; + } + } + + APPL_TRACE_DEBUG("bta_av_conn_chg shdl:%d", index + 1); + for (i = 0; i < BTA_AV_NUM_RCB; i++) { + APPL_TRACE_DEBUG("conn_chg dn[%d]: %d, status=0x%x, shdl:%d, lidx:%d", i, + bta_av_cb.rcb[i].handle, bta_av_cb.rcb[i].status, + bta_av_cb.rcb[i].shdl, bta_av_cb.rcb[i].lidx); + if (bta_av_cb.rcb[i].shdl == index + 1) { + bta_av_del_rc(&bta_av_cb.rcb[i]); + break; + } + } + + if (p_cb->conn_audio == 0 && p_cb->conn_video == 0) { + /* if both channels are not connected, + * close all RC channels */ + bta_av_close_all_rc(p_cb); + } + + /* if the AVRCP is no longer listening, create the listening channel */ + if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG) { + bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + } + } + + APPL_TRACE_DEBUG("bta_av_conn_chg audio:%x video:%x up:%d conn_msk:0x%x chk_restore:%d audio_open_cnt:%d", + p_cb->conn_audio, p_cb->conn_video, p_data->conn_chg.is_up, conn_msk, chk_restore, p_cb->audio_open_cnt); + + if (chk_restore) { + if (p_cb->audio_open_cnt == 1) { + /* one audio channel goes down and there's one audio channel remains open. + * restore the switch role in default link policy */ + bta_sys_set_default_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH); + /* allow role switch, if this is the last connection */ + bta_av_restore_switch(); + } + if (p_cb->audio_open_cnt) { + /* adjust flush timeout settings to longer period */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scbi = bta_av_cb.p_scb[i]; + if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) { + /* may need to update the flush timeout of this already started stream */ + if (p_scbi->co_started != bta_av_cb.audio_open_cnt) { + p_scbi->co_started = bta_av_cb.audio_open_cnt; + L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] ); + } + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_disable +** +** Description disable AV. +** +** Returns void +** +*******************************************************************************/ +void bta_av_disable(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data) +{ + BT_HDR hdr; + UINT16 xx; + UNUSED(p_data); + + p_cb->disabling = TRUE; + + bta_av_close_all_rc(p_cb); + + utl_freebuf((void **) &p_cb->p_disc_db); + + /* disable audio/video - de-register all channels, + * expect BTA_AV_DEREG_COMP_EVT when deregister is complete */ + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + hdr.layer_specific = xx + 1; + bta_av_api_deregister((tBTA_AV_DATA *)&hdr); + } +} + +/******************************************************************************* +** +** Function bta_av_api_disconnect +** +** Description . +** +** Returns void +** +*******************************************************************************/ +void bta_av_api_disconnect(tBTA_AV_DATA *p_data) +{ + AVDT_DisconnectReq(p_data->api_discnt.bd_addr, bta_av_conn_cback); + bta_sys_stop_timer(&bta_av_cb.sig_tmr); +} + +/******************************************************************************* +** +** Function bta_av_sig_chg +** +** Description process AVDT signal channel up/down. +** +** Returns void +** +*******************************************************************************/ +void bta_av_sig_chg(tBTA_AV_DATA *p_data) +{ + UINT16 event = p_data->str_msg.hdr.layer_specific; + tBTA_AV_CB *p_cb = &bta_av_cb; + int xx; + UINT8 mask; + tBTA_AV_LCB *p_lcb = NULL; + + APPL_TRACE_DEBUG("bta_av_sig_chg event: %d", event); + if (event == AVDT_CONNECT_IND_EVT) { + p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FIND); + if (!p_lcb) { + /* if the address does not have an LCB yet, alloc one */ + for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) { + mask = 1 << xx; + APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb); + + /* look for a p_lcb with its p_scb registered */ + if ((!(mask & p_cb->conn_lcb)) && (p_cb->p_scb[xx] != NULL)) { + p_lcb = &p_cb->lcb[xx]; + p_lcb->lidx = xx + 1; + bdcpy(p_lcb->addr, p_data->str_msg.bd_addr); + p_lcb->conn_msk = 0; /* clear the connect mask */ + /* start listening when the signal channel is open */ + if (p_cb->features & BTA_AV_FEAT_RCTG) { + bta_av_rc_create(p_cb, AVCT_ACP, 0, p_lcb->lidx); + } + /* this entry is not used yet. */ + p_cb->conn_lcb |= mask; /* mark it as used */ + APPL_TRACE_DEBUG("start sig timer %d", p_data->hdr.offset); + if (p_data->hdr.offset == AVDT_ACP) { + APPL_TRACE_DEBUG("Incoming L2CAP acquired, set state as incoming"); + bdcpy(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr); + p_cb->p_scb[xx]->use_rc = TRUE; /* allowing RC for incoming connection */ + bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_ACP_CONNECT_EVT, p_data); + + /* The Pending Event should be sent as soon as the L2CAP signalling channel + * is set up, which is NOW. Earlier this was done only after + * BTA_AV_SIG_TIME_VAL milliseconds. + * The following function shall send the event and start the recurring timer + */ + bta_av_sig_timer(NULL); + + /* Possible collision : need to avoid outgoing processing while the timer is running */ + p_cb->p_scb[xx]->coll_mask = BTA_AV_COLL_INC_TMR; + + p_cb->acp_sig_tmr.param = (UINT32)xx; + p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK *)&bta_av_acp_sig_timer_cback; + bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL); + } + break; + } + } + + /* check if we found something */ + if (xx == BTA_AV_NUM_LINKS) { + /* We do not have scb for this avdt connection. */ + /* Silently close the connection. */ + APPL_TRACE_ERROR("av scb not available for avdt connection"); + AVDT_DisconnectReq (p_data->str_msg.bd_addr, NULL); + return; + } + } + } +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + else if (event == BTA_AR_AVDT_CONN_EVT) { + bta_sys_stop_timer(&bta_av_cb.sig_tmr); + } +#endif + else { + /* disconnected. */ + p_lcb = bta_av_find_lcb(p_data->str_msg.bd_addr, BTA_AV_LCB_FREE); + if (p_lcb && p_lcb->conn_msk) { + APPL_TRACE_DEBUG("conn_msk: 0x%x", p_lcb->conn_msk); + /* clean up ssm */ + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + mask = 1 << (xx + 1); + if ((mask & p_lcb->conn_msk) && (p_cb->p_scb[xx]) && + (bdcmp(p_cb->p_scb[xx]->peer_addr, p_data->str_msg.bd_addr) == 0)) { + p_cb->p_scb[xx]->disc_rsn = p_data->str_msg.hdr.offset; + bta_av_ssm_execute(p_cb->p_scb[xx], BTA_AV_AVDT_DISCONNECT_EVT, NULL); + } + } + } + } + APPL_TRACE_DEBUG("conn_lcb: 0x%x", p_cb->conn_lcb); +} + +/******************************************************************************* +** +** Function bta_av_sig_timer +** +** Description process the signal channel timer. This timer is started +** when the AVDTP signal channel is connected. If no profile +** is connected, the timer goes off every BTA_AV_SIG_TIME_VAL +** +** Returns void +** +*******************************************************************************/ +void bta_av_sig_timer(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + int xx; + UINT8 mask; + tBTA_AV_LCB *p_lcb = NULL; + tBTA_AV_PEND pend; + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_sig_timer"); + for (xx = 0; xx < BTA_AV_NUM_LINKS; xx++) { + mask = 1 << xx; + if (mask & p_cb->conn_lcb) { + /* this entry is used. check if it is connected */ + p_lcb = &p_cb->lcb[xx]; + if (!p_lcb->conn_msk) { + bta_sys_start_timer(&p_cb->sig_tmr, BTA_AV_SIG_TIMER_EVT, BTA_AV_SIG_TIME_VAL); + bdcpy(pend.bd_addr, p_lcb->addr); + (*p_cb->p_cback)(BTA_AV_PENDING_EVT, (tBTA_AV *) &pend); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_acp_sig_timer_cback +** +** Description Process the timeout when SRC is accepting connection +** and SNK did not start signalling. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_acp_sig_timer_cback (TIMER_LIST_ENT *p_tle) +{ + UINT8 inx = (UINT8)p_tle->param; + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb = NULL; + tBTA_AV_API_OPEN *p_buf; + if (inx < BTA_AV_NUM_STRS) { + p_scb = p_cb->p_scb[inx]; + } + if (p_scb) { + APPL_TRACE_DEBUG("bta_av_acp_sig_timer_cback, coll_mask = 0x%02X", p_scb->coll_mask); + + if (p_scb->coll_mask & BTA_AV_COLL_INC_TMR) { + p_scb->coll_mask &= ~BTA_AV_COLL_INC_TMR; + + if (bta_av_is_scb_opening(p_scb)) { + if (p_scb->p_disc_db) { + /* We are still doing SDP. Run the timer again. */ + p_scb->coll_mask |= BTA_AV_COLL_INC_TMR; + + p_cb->acp_sig_tmr.param = (UINT32)inx; + p_cb->acp_sig_tmr.p_cback = (TIMER_CBACK *)&bta_av_acp_sig_timer_cback; + bta_sys_start_timer(&p_cb->acp_sig_tmr, 0, BTA_AV_ACP_SIG_TIME_VAL); + } else { + /* SNK did not start signalling, resume signalling process. */ + bta_av_discover_req (p_scb, NULL); + } + } else if (bta_av_is_scb_incoming(p_scb)) { + /* Stay in incoming state if SNK does not start signalling */ + + /* API open was called right after SNK opened L2C connection. */ + if (p_scb->coll_mask & BTA_AV_COLL_API_CALLED) { + p_scb->coll_mask &= ~BTA_AV_COLL_API_CALLED; + + /* BTA_AV_API_OPEN_EVT */ + if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL) { + memcpy(p_buf, &(p_scb->open_api), sizeof(tBTA_AV_API_OPEN)); + bta_sys_sendmsg(p_buf); + } + } + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_check_peer_features +** +** Description check supported features on the peer device from the SDP record +** and return the feature mask +** +** Returns tBTA_AV_FEAT peer device feature mask +** +*******************************************************************************/ +tBTA_AV_FEAT bta_av_check_peer_features (UINT16 service_uuid) +{ + tBTA_AV_FEAT peer_features = 0; + tBTA_AV_CB *p_cb = &bta_av_cb; + tSDP_DISC_REC *p_rec = NULL; + tSDP_DISC_ATTR *p_attr; + UINT16 peer_rc_version = 0; + UINT16 categories = 0; + + APPL_TRACE_DEBUG("bta_av_check_peer_features service_uuid:x%x", service_uuid); + /* loop through all records we found */ + while (TRUE) { + /* get next record; if none found, we're done */ + if ((p_rec = SDP_FindServiceInDb(p_cb->p_disc_db, service_uuid, p_rec)) == NULL) { + break; + } + + if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_SERVICE_CLASS_ID_LIST)) != NULL) { + /* find peer features */ + if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL)) { + peer_features |= BTA_AV_FEAT_RCCT; + } + if (SDP_FindServiceInDb(p_cb->p_disc_db, UUID_SERVCLASS_AV_REM_CTRL_TARGET, NULL)) { + peer_features |= BTA_AV_FEAT_RCTG; + } + } + + if (( SDP_FindAttributeInRec(p_rec, ATTR_ID_BT_PROFILE_DESC_LIST)) != NULL) { + /* get profile version (if failure, version parameter is not updated) */ + SDP_FindProfileVersionInRec(p_rec, UUID_SERVCLASS_AV_REMOTE_CONTROL, &peer_rc_version); + APPL_TRACE_DEBUG("peer_rc_version 0x%x", peer_rc_version); + + if (peer_rc_version >= AVRC_REV_1_3) { + peer_features |= (BTA_AV_FEAT_VENDOR | BTA_AV_FEAT_METADATA); + } + + if (peer_rc_version >= AVRC_REV_1_4) { + peer_features |= (BTA_AV_FEAT_ADV_CTRL); + /* get supported categories */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, + ATTR_ID_SUPPORTED_FEATURES)) != NULL) { + categories = p_attr->attr_value.v.u16; + if (categories & AVRC_SUPF_CT_BROWSE) { + peer_features |= (BTA_AV_FEAT_BROWSE); + } + } + } + } + } + APPL_TRACE_DEBUG("peer_features:x%x", peer_features); + return peer_features; +} + +/******************************************************************************* +** +** Function bta_av_rc_disc_done +** +** Description Handle AVRCP service discovery results. If matching +** service found, open AVRCP connection. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_disc_done(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb = NULL; + tBTA_AV_LCB *p_lcb; + tBTA_AV_RC_OPEN rc_open; + tBTA_AV_RC_FEAT rc_feat; + UINT8 rc_handle; + tBTA_AV_FEAT peer_features; /* peer features mask */ + UNUSED(p_data); + + APPL_TRACE_DEBUG("bta_av_rc_disc_done disc:x%x", p_cb->disc); + if (!p_cb->disc) { + return; + } + + if ((p_cb->disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) { + /* this is the rc handle/index to tBTA_AV_RCB */ + rc_handle = p_cb->disc & (~BTA_AV_CHNL_MSK); + } else { + /* Validate array index*/ + if (((p_cb->disc & BTA_AV_HNDL_MSK) - 1) < BTA_AV_NUM_STRS) { + p_scb = p_cb->p_scb[(p_cb->disc & BTA_AV_HNDL_MSK) - 1]; + } + if (p_scb) { + rc_handle = p_scb->rc_handle; + } else { + p_cb->disc = 0; + return; + } + } + + APPL_TRACE_DEBUG("rc_handle %d", rc_handle); + /* check peer version and whether support CT and TG role */ + peer_features = bta_av_check_peer_features (UUID_SERVCLASS_AV_REMOTE_CONTROL); + if ((p_cb->features & BTA_AV_FEAT_ADV_CTRL) && ((peer_features & BTA_AV_FEAT_ADV_CTRL) == 0)) { + /* if we support advance control and peer does not, check their support on TG role + * some implementation uses 1.3 on CT ans 1.4 on TG */ + peer_features |= bta_av_check_peer_features (UUID_SERVCLASS_AV_REM_CTRL_TARGET); + } + + p_cb->disc = 0; + utl_freebuf((void **) &p_cb->p_disc_db); + + APPL_TRACE_DEBUG("peer_features 0x%x, features 0x%x", peer_features, p_cb->features); + + /* if we have no rc connection */ + if (rc_handle == BTA_AV_RC_HANDLE_NONE) { + if (p_scb) { + /* if peer remote control service matches ours and USE_RC is TRUE */ + if ((((p_cb->features & BTA_AV_FEAT_RCCT) && (peer_features & BTA_AV_FEAT_RCTG)) || + ((p_cb->features & BTA_AV_FEAT_RCTG) && (peer_features & BTA_AV_FEAT_RCCT))) ) { + p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND); + if (p_lcb) { + rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx); + p_cb->rcb[rc_handle].peer_features = peer_features; + } +#if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE) + else { + APPL_TRACE_ERROR("can not find LCB!!"); + } +#endif + } else if (p_scb->use_rc) { + /* can not find AVRC on peer device. report failure */ + p_scb->use_rc = FALSE; + bdcpy(rc_open.peer_addr, p_scb->peer_addr); + rc_open.peer_features = 0; + rc_open.status = BTA_AV_FAIL_SDP; + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open); + } + } + } else { + p_cb->rcb[rc_handle].peer_features = peer_features; + rc_feat.rc_handle = rc_handle; + rc_feat.peer_features = peer_features; + (*p_cb->p_cback)(BTA_AV_RC_FEAT_EVT, (tBTA_AV *) &rc_feat); + } +} + +/******************************************************************************* +** +** Function bta_av_rc_closed +** +** Description Set AVRCP state to closed. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_closed(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_RC_CLOSE rc_close; + tBTA_AV_RC_CONN_CHG *p_msg = (tBTA_AV_RC_CONN_CHG *)p_data; + tBTA_AV_RCB *p_rcb; + tBTA_AV_SCB *p_scb; + int i; + BOOLEAN conn = FALSE; + tBTA_AV_LCB *p_lcb; + + rc_close.rc_handle = BTA_AV_RC_HANDLE_NONE; + p_scb = NULL; + APPL_TRACE_DEBUG("bta_av_rc_closed rc_handle:%d", p_msg->handle); + for (i = 0; i < BTA_AV_NUM_RCB; i++) { + p_rcb = &p_cb->rcb[i]; + APPL_TRACE_DEBUG("bta_av_rc_closed rcb[%d] rc_handle:%d, status=0x%x", i, p_rcb->handle, p_rcb->status); + if (p_rcb->handle == p_msg->handle) { + rc_close.rc_handle = i; + p_rcb->status &= ~BTA_AV_RC_CONN_MASK; + p_rcb->peer_features = 0; + APPL_TRACE_DEBUG(" shdl:%d, lidx:%d", p_rcb->shdl, p_rcb->lidx); + if (p_rcb->shdl) { + if ((p_rcb->shdl - 1) < BTA_AV_NUM_STRS) { + p_scb = bta_av_cb.p_scb[p_rcb->shdl - 1]; + } + if (p_scb) { + bdcpy(rc_close.peer_addr, p_scb->peer_addr); + if (p_scb->rc_handle == p_rcb->handle) { + p_scb->rc_handle = BTA_AV_RC_HANDLE_NONE; + } + APPL_TRACE_DEBUG("shdl:%d, srch:%d", p_rcb->shdl, p_scb->rc_handle); + } + p_rcb->shdl = 0; + } else if (p_rcb->lidx == (BTA_AV_NUM_LINKS + 1) ) { + /* if the RCB uses the extra LCB, use the addr for event and clean it */ + p_lcb = &p_cb->lcb[BTA_AV_NUM_LINKS]; + bdcpy(rc_close.peer_addr, p_msg->peer_addr); + APPL_TRACE_DEBUG("rc_only closed bd_addr:%02x-%02x-%02x-%02x-%02x-%02x", + p_msg->peer_addr[0], p_msg->peer_addr[1], + p_msg->peer_addr[2], p_msg->peer_addr[3], + p_msg->peer_addr[4], p_msg->peer_addr[5]); + p_lcb->conn_msk = 0; + p_lcb->lidx = 0; + } + p_rcb->lidx = 0; + + if ((p_rcb->status & BTA_AV_RC_ROLE_MASK) == BTA_AV_RC_ROLE_INT) { + /* AVCT CCB is deallocated */ + p_rcb->handle = BTA_AV_RC_HANDLE_NONE; + p_rcb->status = 0; + } else { + /* AVCT CCB is still there. dealloc */ + bta_av_del_rc(p_rcb); + + /* if the AVRCP is no longer listening, create the listening channel */ + if (bta_av_cb.rc_acp_handle == BTA_AV_RC_HANDLE_NONE && bta_av_cb.features & BTA_AV_FEAT_RCTG) { + bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + } + } + } else if ((p_rcb->handle != BTA_AV_RC_HANDLE_NONE) && (p_rcb->status & BTA_AV_RC_CONN_MASK)) { + /* at least one channel is still connected */ + conn = TRUE; + } + } + + if (!conn) { + /* no AVRC channels are connected, go back to INIT state */ + bta_av_sm_execute(p_cb, BTA_AV_AVRC_NONE_EVT, NULL); + } + + if (rc_close.rc_handle == BTA_AV_RC_HANDLE_NONE) { + rc_close.rc_handle = p_msg->handle; + bdcpy(rc_close.peer_addr, p_msg->peer_addr); + } + (*p_cb->p_cback)(BTA_AV_RC_CLOSE_EVT, (tBTA_AV *) &rc_close); +} + +/******************************************************************************* +** +** Function bta_av_rc_disc +** +** Description start AVRC SDP discovery. +** +** Returns void +** +*******************************************************************************/ +void bta_av_rc_disc(UINT8 disc) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tAVRC_SDP_DB_PARAMS db_params; + UINT16 attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, + ATTR_ID_BT_PROFILE_DESC_LIST, + ATTR_ID_SUPPORTED_FEATURES + }; + UINT8 hdi; + tBTA_AV_SCB *p_scb; + UINT8 *p_addr = NULL; + UINT8 rc_handle; + + APPL_TRACE_DEBUG("bta_av_rc_disc 0x%x, %d", disc, bta_av_cb.disc); + if ((bta_av_cb.disc != 0) || (disc == 0)) { + return; + } + + if ((disc & BTA_AV_CHNL_MSK) == BTA_AV_CHNL_MSK) { + /* this is the rc handle/index to tBTA_AV_RCB */ + rc_handle = disc & (~BTA_AV_CHNL_MSK); + if (p_cb->rcb[rc_handle].lidx) { + p_addr = p_cb->lcb[p_cb->rcb[rc_handle].lidx - 1].addr; + } + } else { + hdi = (disc & BTA_AV_HNDL_MSK) - 1; + p_scb = p_cb->p_scb[hdi]; + + if (p_scb) { + APPL_TRACE_DEBUG("rc_handle %d", p_scb->rc_handle); + p_addr = p_scb->peer_addr; + } + } + + if (p_addr) { + /* allocate discovery database */ + if (p_cb->p_disc_db == NULL) { + p_cb->p_disc_db = (tSDP_DISCOVERY_DB *) GKI_getbuf(BTA_AV_DISC_BUF_SIZE); + } + + if (p_cb->p_disc_db) { + /* set up parameters */ + db_params.db_len = BTA_AV_DISC_BUF_SIZE; + db_params.num_attr = 3; + db_params.p_db = p_cb->p_disc_db; + db_params.p_attrs = attr_list; + + /* searching for UUID_SERVCLASS_AV_REMOTE_CONTROL gets both TG and CT */ + if (AVRC_FindService(UUID_SERVCLASS_AV_REMOTE_CONTROL, p_addr, &db_params, + bta_av_avrc_sdp_cback) == AVRC_SUCCESS) { + p_cb->disc = disc; + APPL_TRACE_DEBUG("disc %d", p_cb->disc); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_dereg_comp +** +** Description deregister complete. free the stream control block. +** +** Returns void +** +*******************************************************************************/ +void bta_av_dereg_comp(tBTA_AV_DATA *p_data) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + tBTA_AV_SCB *p_scb; + tBTA_UTL_COD cod; + UINT8 mask; + BT_HDR *p_buf; + + /* find the stream control block */ + p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific); + + if (p_scb) { + APPL_TRACE_DEBUG("deregistered %d(h%d)", p_scb->chnl, p_scb->hndl); + mask = BTA_AV_HNDL_TO_MSK(p_scb->hdi); + if (p_scb->chnl == BTA_AV_CHNL_AUDIO) { + p_cb->reg_audio &= ~mask; + if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) { + /* this channel is still marked as open. decrease the count */ + bta_av_cb.audio_open_cnt--; + } + p_cb->conn_audio &= ~mask; + + if (p_scb->q_tag == BTA_AV_Q_TAG_STREAM && p_scb->a2d_list) { + /* make sure no buffers are in a2d_list */ + while (!list_is_empty(p_scb->a2d_list)) { + p_buf = (BT_HDR *)list_front(p_scb->a2d_list); + list_remove(p_scb->a2d_list, p_buf); + GKI_freebuf(p_buf); + } + } + + /* remove the A2DP SDP record, if no more audio stream is left */ + if (!p_cb->reg_audio) { +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REMOTE_CONTROL, BTA_ID_AV); +#endif + bta_av_del_sdp_rec(&p_cb->sdp_a2d_handle); + bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SOURCE); + +#if (BTA_AV_SINK_INCLUDED == TRUE) + bta_av_del_sdp_rec(&p_cb->sdp_a2d_snk_handle); + bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK); +#endif + } + } else { + p_cb->reg_video &= ~mask; + /* make sure that this channel is not connected */ + p_cb->conn_video &= ~mask; + /* remove the VDP SDP record, (only one video stream at most) */ + bta_av_del_sdp_rec(&p_cb->sdp_vdp_handle); + bta_sys_remove_uuid(UUID_SERVCLASS_VIDEO_SOURCE); + } + + /* make sure that the timer is not active */ + bta_sys_stop_timer(&p_scb->timer); + utl_freebuf((void **)&p_cb->p_scb[p_scb->hdi]); + } + + APPL_TRACE_DEBUG("audio 0x%x, video: 0x%x, disable:%d", + p_cb->reg_audio, p_cb->reg_video, p_cb->disabling); + /* if no stream control block is active */ + if ((p_cb->reg_audio + p_cb->reg_video) == 0) { +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + /* deregister from AVDT */ + bta_ar_dereg_avdt(BTA_ID_AV); + + /* deregister from AVCT */ + bta_ar_dereg_avrc (UUID_SERVCLASS_AV_REM_CTRL_TARGET, BTA_ID_AV); + bta_ar_dereg_avct(BTA_ID_AV); +#endif + + if (p_cb->disabling) { + p_cb->disabling = FALSE; + bta_av_cb.features = 0; + } + + /* Clear the Capturing service class bit */ + cod.service = BTM_COD_SERVICE_CAPTURING; + utl_set_device_class(&cod, BTA_UTL_CLR_COD_SERVICE_CLASS); + } +} +#endif /* BTA_AV_INCLUDED */ diff --git a/components/bt/bluedroid/bta/av/bta_av_api.c b/components/bt/bluedroid/bta/av/bta_av_api.c new file mode 100644 index 0000000000..0da44643d7 --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_api.c @@ -0,0 +1,573 @@ +/****************************************************************************** + * + * Copyright (C) 2011-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the implementation of the API for the advanced audio/video (AV) + * subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_av_api.h" +#include "bta_av_int.h" +#include "gki.h" +#include + +/***************************************************************************** +** Constants +*****************************************************************************/ + +static const tBTA_SYS_REG bta_av_reg = { + bta_av_hdl_event, + BTA_AvDisable +}; + +/******************************************************************************* +** +** Function BTA_AvEnable +** +** Description Enable the advanced audio/video service. When the enable +** operation is complete the callback function will be +** called with a BTA_AV_ENABLE_EVT. This function must +** be called before other function in the AV API are +** called. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, tBTA_AV_CBACK *p_cback) +{ + tBTA_AV_API_ENABLE *p_buf; + + /* register with BTA system manager */ + bta_sys_register(BTA_ID_AV, &bta_av_reg); + + if ((p_buf = (tBTA_AV_API_ENABLE *) GKI_getbuf(sizeof(tBTA_AV_API_ENABLE))) != NULL) { + p_buf->hdr.event = BTA_AV_API_ENABLE_EVT; + p_buf->p_cback = p_cback; + p_buf->features = features; + p_buf->sec_mask = sec_mask; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvDisable +** +** Description Disable the advanced audio/video service. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDisable(void) +{ + BT_HDR *p_buf; + + bta_sys_deregister(BTA_ID_AV); + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_AV_API_DISABLE_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvRegister +** +** Description Register the audio or video service to stack. When the +** operation is complete the callback function will be +** called with a BTA_AV_REGISTER_EVT. This function must +** be called before AVDT stream is open. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback, tBTA_AV_CO_FUNCTS *bta_av_cos) +{ + tBTA_AV_API_REG *p_buf; + + + if ((p_buf = (tBTA_AV_API_REG *) GKI_getbuf(sizeof(tBTA_AV_API_REG))) != NULL) { + p_buf->hdr.layer_specific = chnl; + p_buf->hdr.event = BTA_AV_API_REGISTER_EVT; + if (p_service_name) { + BCM_STRNCPY_S(p_buf->p_service_name, sizeof(p_buf->p_service_name), p_service_name, BTA_SERVICE_NAME_LEN); + p_buf->p_service_name[BTA_SERVICE_NAME_LEN - 1] = 0; + } else { + p_buf->p_service_name[0] = 0; + } + p_buf->app_id = app_id; + p_buf->p_app_data_cback = p_data_cback; + p_buf->bta_av_cos = bta_av_cos; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvDeregister +** +** Description Deregister the audio or video service +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDeregister(tBTA_AV_HNDL hndl) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_buf->layer_specific = hndl; + p_buf->event = BTA_AV_API_DEREGISTER_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvOpen +** +** Description Opens an advanced audio/video connection to a peer device. +** When connection is open callback function is called +** with a BTA_AV_OPEN_EVT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, BOOLEAN use_rc, tBTA_SEC sec_mask, + UINT16 uuid) +{ + tBTA_AV_API_OPEN *p_buf; + + if ((p_buf = (tBTA_AV_API_OPEN *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN))) != NULL) { + p_buf->hdr.event = BTA_AV_API_OPEN_EVT; + p_buf->hdr.layer_specific = handle; + bdcpy(p_buf->bd_addr, bd_addr); + p_buf->use_rc = use_rc; + p_buf->sec_mask = sec_mask; + p_buf->switch_res = BTA_AV_RS_NONE; + p_buf->uuid = uuid; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvClose +** +** Description Close the current streams. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvClose(tBTA_AV_HNDL handle) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_AV_API_CLOSE_EVT; + p_buf->layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvDisconnect +** +** Description Close the connection to the address. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDisconnect(BD_ADDR bd_addr) +{ + tBTA_AV_API_DISCNT *p_buf; + + if ((p_buf = (tBTA_AV_API_DISCNT *) GKI_getbuf(sizeof(tBTA_AV_API_DISCNT))) != NULL) { + p_buf->hdr.event = BTA_AV_API_DISCONNECT_EVT; + bdcpy(p_buf->bd_addr, bd_addr); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvStart +** +** Description Start audio/video stream data transfer. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvStart(void) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_AV_API_START_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvEnable_Sink +** +** Description Enable/Disable A2DP Sink.. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvEnable_Sink(int enable) +{ +#if (BTA_AV_SINK_INCLUDED == TRUE) + BT_HDR *p_buf; + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_buf->event = BTA_AV_API_SINK_ENABLE_EVT; + p_buf->layer_specific = enable; + bta_sys_sendmsg(p_buf); + } +#else + return; +#endif +} + +/******************************************************************************* +** +** Function BTA_AvStop +** +** Description Stop audio/video stream data transfer. +** If suspend is TRUE, this function sends AVDT suspend signal +** to the connected peer(s). +** +** Returns void +** +*******************************************************************************/ +void BTA_AvStop(BOOLEAN suspend) +{ + tBTA_AV_API_STOP *p_buf; + + if ((p_buf = (tBTA_AV_API_STOP *) GKI_getbuf(sizeof(tBTA_AV_API_STOP))) != NULL) { + p_buf->hdr.event = BTA_AV_API_STOP_EVT; + p_buf->flush = TRUE; + p_buf->suspend = suspend; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvReconfig +** +** Description Reconfigure the audio/video stream. +** If suspend is TRUE, this function tries the suspend/reconfigure +** procedure first. +** If suspend is FALSE or when suspend/reconfigure fails, +** this function closes and re-opens the AVDT connection. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvReconfig(tBTA_AV_HNDL hndl, BOOLEAN suspend, UINT8 sep_info_idx, + UINT8 *p_codec_info, UINT8 num_protect, UINT8 *p_protect_info) +{ + tBTA_AV_API_RCFG *p_buf; + + if ((p_buf = (tBTA_AV_API_RCFG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_RCFG) + num_protect))) != NULL) { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = BTA_AV_API_RECONFIG_EVT; + p_buf->num_protect = num_protect; + p_buf->suspend = suspend; + p_buf->sep_info_idx = sep_info_idx; + p_buf->p_protect_info = (UINT8 *)(p_buf + 1); + memcpy(p_buf->codec_info, p_codec_info, AVDT_CODEC_SIZE); + memcpy(p_buf->p_protect_info, p_protect_info, num_protect); + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvProtectReq +** +** Description Send a content protection request. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvProtectReq(tBTA_AV_HNDL hndl, UINT8 *p_data, UINT16 len) +{ + tBTA_AV_API_PROTECT_REQ *p_buf; + + if ((p_buf = (tBTA_AV_API_PROTECT_REQ *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_REQ) + len))) != NULL) { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = BTA_AV_API_PROTECT_REQ_EVT; + p_buf->len = len; + if (p_data == NULL) { + p_buf->p_data = NULL; + } else { + p_buf->p_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->p_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvProtectRsp +** +** Description Send a content protection response. This function must +** be called if a BTA_AV_PROTECT_REQ_EVT is received. +** This function can only be used if AV is enabled with +** feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, UINT8 error_code, UINT8 *p_data, UINT16 len) +{ + tBTA_AV_API_PROTECT_RSP *p_buf; + + if ((p_buf = (tBTA_AV_API_PROTECT_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_PROTECT_RSP) + len))) != NULL) { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = BTA_AV_API_PROTECT_RSP_EVT; + p_buf->len = len; + p_buf->error_code = error_code; + if (p_data == NULL) { + p_buf->p_data = NULL; + } else { + p_buf->p_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->p_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvRemoteCmd +** +** Description Send a remote control command. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_RCCT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id, tBTA_AV_STATE key_state) +{ + tBTA_AV_API_REMOTE_CMD *p_buf; + + if ((p_buf = (tBTA_AV_API_REMOTE_CMD *) GKI_getbuf(sizeof(tBTA_AV_API_REMOTE_CMD))) != NULL) { + p_buf->hdr.event = BTA_AV_API_REMOTE_CMD_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->msg.op_id = rc_id; + p_buf->msg.state = key_state; + p_buf->msg.p_pass_data = NULL; + p_buf->msg.pass_len = 0; + p_buf->label = label; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvVendorCmd +** +** Description Send a vendor dependent remote control command. This +** function can only be used if AV is enabled with feature +** BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvVendorCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE cmd_code, UINT8 *p_data, UINT16 len) +{ + tBTA_AV_API_VENDOR *p_buf; + + if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL) { + p_buf->hdr.event = BTA_AV_API_VENDOR_CMD_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->msg.hdr.ctype = cmd_code; + p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL; + p_buf->msg.hdr.subunit_id = 0; + p_buf->msg.company_id = p_bta_av_cfg->company_id; + p_buf->label = label; + p_buf->msg.vendor_len = len; + if (p_data == NULL) { + p_buf->msg.p_vendor_data = NULL; + } else { + p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->msg.p_vendor_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvVendorRsp +** +** Description Send a vendor dependent remote control response. +** This function must be called if a BTA_AV_VENDOR_CMD_EVT +** is received. This function can only be used if AV is +** enabled with feature BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvVendorRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, UINT8 *p_data, UINT16 len, UINT32 company_id) +{ + tBTA_AV_API_VENDOR *p_buf; + + if ((p_buf = (tBTA_AV_API_VENDOR *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_VENDOR) + len))) != NULL) { + p_buf->hdr.event = BTA_AV_API_VENDOR_RSP_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->msg.hdr.ctype = rsp_code; + p_buf->msg.hdr.subunit_type = AVRC_SUB_PANEL; + p_buf->msg.hdr.subunit_id = 0; + if (company_id) { + p_buf->msg.company_id = company_id; + } else { + p_buf->msg.company_id = p_bta_av_cfg->company_id; + } + p_buf->label = label; + p_buf->msg.vendor_len = len; + if (p_data == NULL) { + p_buf->msg.p_vendor_data = NULL; + } else { + p_buf->msg.p_vendor_data = (UINT8 *) (p_buf + 1); + memcpy(p_buf->msg.p_vendor_data, p_data, len); + } + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvOpenRc +** +** Description Open an AVRCP connection toward the device with the +** specified handle +** +** Returns void +** +*******************************************************************************/ +void BTA_AvOpenRc(tBTA_AV_HNDL handle) +{ + tBTA_AV_API_OPEN_RC *p_buf; + + if ((p_buf = (tBTA_AV_API_OPEN_RC *) GKI_getbuf(sizeof(tBTA_AV_API_OPEN_RC))) != NULL) { + p_buf->hdr.event = BTA_AV_API_RC_OPEN_EVT; + p_buf->hdr.layer_specific = handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvCloseRc +** +** Description Close an AVRCP connection +** +** Returns void +** +*******************************************************************************/ +void BTA_AvCloseRc(UINT8 rc_handle) +{ + tBTA_AV_API_CLOSE_RC *p_buf; + + if ((p_buf = (tBTA_AV_API_CLOSE_RC *) GKI_getbuf(sizeof(tBTA_AV_API_CLOSE_RC))) != NULL) { + p_buf->hdr.event = BTA_AV_API_RC_CLOSE_EVT; + p_buf->hdr.layer_specific = rc_handle; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function BTA_AvMetaRsp +** +** Description Send a Metadata/Advanced Control response. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvMetaRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, + BT_HDR *p_pkt) +{ + tBTA_AV_API_META_RSP *p_buf; + + if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL) { + p_buf->hdr.event = BTA_AV_API_META_RSP_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->rsp_code = rsp_code; + p_buf->p_pkt = p_pkt; + p_buf->is_rsp = TRUE; + p_buf->label = label; + + bta_sys_sendmsg(p_buf); + } else if (p_pkt) { + GKI_freebuf(p_pkt); + } +} + +/******************************************************************************* +** +** Function BTA_AvMetaCmd +** +** Description Send a Metadata/Advanced Control command. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** This message is sent only when the peer supports the TG role. +*8 The only command makes sense right now is the absolute volume command. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt) +{ + tBTA_AV_API_META_RSP *p_buf; + + if ((p_buf = (tBTA_AV_API_META_RSP *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_API_META_RSP)))) != NULL) { + p_buf->hdr.event = BTA_AV_API_META_RSP_EVT; + p_buf->hdr.layer_specific = rc_handle; + p_buf->p_pkt = p_pkt; + p_buf->rsp_code = cmd_code; + p_buf->is_rsp = FALSE; + p_buf->label = label; + + bta_sys_sendmsg(p_buf); + } +} + +#endif /* BTA_AV_INCLUDED */ diff --git a/components/bt/bluedroid/bta/av/bta_av_cfg.c b/components/bt/bluedroid/bta/av/bta_av_cfg.c new file mode 100644 index 0000000000..d057eee298 --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_cfg.c @@ -0,0 +1,208 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains compile-time configurable constants for advanced + * audio/video + * + ******************************************************************************/ + +#include + +#include "bt_target.h" +#include "gki.h" +#include "bta_api.h" +#include "bta_av_int.h" + +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#ifndef BTA_AV_RC_PASS_RSP_CODE +#define BTA_AV_RC_PASS_RSP_CODE BTA_AV_RSP_NOT_IMPL +#endif + +const UINT32 bta_av_meta_caps_co_ids[] = { + AVRC_CO_METADATA, + AVRC_CO_BROADCOM +}; + +/* AVRCP cupported categories */ +#define BTA_AV_RC_SUPF_CT (AVRC_SUPF_CT_CAT2) + +/* Added to modify +** 1. flush timeout +** 2. Remove Group navigation support in SupportedFeatures +** 3. GetCapabilities supported event_ids list +** 4. GetCapabilities supported event_ids count +*/ +/* Flushing partial avdtp packets can cause some headsets to disconnect the link + if receiving partial a2dp frames */ +const UINT16 bta_av_audio_flush_to[] = { + 0, /* 1 stream */ + 0, /* 2 streams */ + 0, /* 3 streams */ + 0, /* 4 streams */ + 0 /* 5 streams */ +}; /* AVDTP audio transport channel flush timeout */ + +/* Note: Android doesnt support AVRC_SUPF_TG_GROUP_NAVI */ +/* Note: if AVRC_SUPF_TG_GROUP_NAVI is set, bta_av_cfg.avrc_group should be TRUE */ +#if AVRC_METADATA_INCLUDED == TRUE +#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) /* TODO: | AVRC_SUPF_TG_APP_SETTINGS) */ +#else +#define BTA_AV_RC_SUPF_TG (AVRC_SUPF_TG_CAT1) +#endif + +/* + * If the number of event IDs is changed in this array, BTA_AV_ NUM_RC_EVT_IDS also needs to be changed. + */ +const UINT8 bta_av_meta_caps_evt_ids[] = { + AVRC_EVT_PLAY_STATUS_CHANGE, + AVRC_EVT_TRACK_CHANGE, + AVRC_EVT_PLAY_POS_CHANGED, + /* TODO: Add support for these events + AVRC_EVT_APP_SETTING_CHANGE, + */ +}; +#ifndef BTA_AV_NUM_RC_EVT_IDS +#define BTA_AV_NUM_RC_EVT_IDS (sizeof(bta_av_meta_caps_evt_ids) / sizeof(bta_av_meta_caps_evt_ids[0])) +#endif /* BTA_AV_NUM_RC_EVT_IDS */ + +/* the MTU for the AVRCP browsing channel */ +#ifndef BTA_AV_MAX_RC_BR_MTU +#define BTA_AV_MAX_RC_BR_MTU 1008 +#endif + +const tBTA_AV_CFG bta_av_cfg = { + AVRC_CO_BROADCOM, /* AVRCP Company ID */ +#if AVRC_METADATA_INCLUDED == TRUE + 512, /* AVRCP MTU at L2CAP for control channel */ +#else + 48, /* AVRCP MTU at L2CAP for control channel */ +#endif + BTA_AV_MAX_RC_BR_MTU, /* AVRCP MTU at L2CAP for browsing channel */ + BTA_AV_RC_SUPF_CT, /* AVRCP controller categories */ + BTA_AV_RC_SUPF_TG, /* AVRCP target categories */ + 672, /* AVDTP signaling channel MTU at L2CAP */ + BTA_AV_MAX_A2DP_MTU, /* AVDTP audio transport channel MTU at L2CAP */ + bta_av_audio_flush_to, /* AVDTP audio transport channel flush timeout */ + 6, /* AVDTP audio channel max data queue size */ + BTA_AV_MAX_VDP_MTU, /* AVDTP video transport channel MTU at L2CAP */ + 600, /* AVDTP video transport channel flush timeout */ + FALSE, /* TRUE, to accept AVRC 1.3 group nevigation command */ + 2, /* company id count in p_meta_co_ids */ + BTA_AV_NUM_RC_EVT_IDS, /* event id count in p_meta_evt_ids */ + BTA_AV_RC_PASS_RSP_CODE,/* the default response code for pass through commands */ + bta_av_meta_caps_co_ids,/* the metadata Get Capabilities response for company id */ + bta_av_meta_caps_evt_ids,/* the the metadata Get Capabilities response for event id */ + NULL, /* the action function table for VDP stream */ + NULL, /* action function to register VDP */ + {0}, /* Default AVRCP controller name */ + {0}, /* Default AVRCP target name */ +}; + +tBTA_AV_CFG *p_bta_av_cfg = (tBTA_AV_CFG *) &bta_av_cfg; + +const UINT16 bta_av_rc_id[] = { + 0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT, + 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP, + 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU, + 12=FAV_MENU, 13=EXIT */ + + 0, /* not used */ + + 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3, + 4=4, 5=5, 6=6, 7=7, + 8=8, 9=9, 10=DOT, 11=ENTER, + 12=CLEAR */ + + 0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL, + 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP, + 8=PAGE_DOWN */ + +#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM) + /* btui_app provides an example of how to leave the decision of rejecting a command or not + * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later) + * If the decision is per player for a particular rc_id, the related bit is clear (not set) */ + 0x0070, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ +#else +#if (defined BTA_AVRCP_FF_RW_SUPPORT) && (BTA_AVRCP_FF_RW_SUPPORT == TRUE) + 0x1b70, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ +#else + 0x1870, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ +#endif +#endif + + 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */ + + 0, /* not used */ + + 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3, + 4=F4, 5=F5 */ +}; + +#if (BTA_AV_RC_PASS_RSP_CODE == BTA_AV_RSP_INTERIM) +const UINT16 bta_av_rc_id_ac[] = { + 0x0000, /* bit mask: 0=SELECT, 1=UP, 2=DOWN, 3=LEFT, + 4=RIGHT, 5=RIGHT_UP, 6=RIGHT_DOWN, 7=LEFT_UP, + 8=LEFT_DOWN, 9=ROOT_MENU, 10=SETUP_MENU, 11=CONT_MENU, + 12=FAV_MENU, 13=EXIT */ + + 0, /* not used */ + + 0x0000, /* bit mask: 0=0, 1=1, 2=2, 3=3, + 4=4, 5=5, 6=6, 7=7, + 8=8, 9=9, 10=DOT, 11=ENTER, + 12=CLEAR */ + + 0x0000, /* bit mask: 0=CHAN_UP, 1=CHAN_DOWN, 2=PREV_CHAN, 3=SOUND_SEL, + 4=INPUT_SEL, 5=DISP_INFO, 6=HELP, 7=PAGE_UP, + 8=PAGE_DOWN */ + + /* btui_app provides an example of how to leave the decision of rejecting a command or not + * based on which media player is currently addressed (this is only applicable for AVRCP 1.4 or later) + * If the decision is per player for a particular rc_id, the related bit is set */ + 0x1800, /* bit mask: 0=POWER, 1=VOL_UP, 2=VOL_DOWN, 3=MUTE, + 4=PLAY, 5=STOP, 6=PAUSE, 7=RECORD, + 8=REWIND, 9=FAST_FOR, 10=EJECT, 11=FORWARD, + 12=BACKWARD */ + + 0x0000, /* bit mask: 0=ANGLE, 1=SUBPICT */ + + 0, /* not used */ + + 0x0000 /* bit mask: 0=not used, 1=F1, 2=F2, 3=F3, + 4=F4, 5=F5 */ +}; +UINT16 *p_bta_av_rc_id_ac = (UINT16 *) bta_av_rc_id_ac; +#else +UINT16 *p_bta_av_rc_id_ac = NULL; +#endif + +UINT16 *p_bta_av_rc_id = (UINT16 *) bta_av_rc_id; + +#endif /* if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/av/bta_av_ci.c b/components/bt/bluedroid/bta/av/bta_av_ci.c new file mode 100644 index 0000000000..11a47dc74d --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_ci.c @@ -0,0 +1,97 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the implementation file for advanced audio/video call-in + * functions. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "bta_api.h" +#include "bta_sys.h" +#include "bta_av_int.h" +#include "bta_av_ci.h" + +#include + +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_av_ci_src_data_ready +** +** Description This function sends an event to the AV indicating that +** the phone has audio stream data ready to send and AV +** should call bta_av_co_audio_src_data_path() or +** bta_av_co_video_src_data_path(). +** +** Returns void +** +*******************************************************************************/ +void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl) +{ + BT_HDR *p_buf; + + if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + p_buf->layer_specific = chnl; + p_buf->event = BTA_AV_CI_SRC_DATA_READY_EVT; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_ci_setconfig +** +** Description This function must be called in response to function +** bta_av_co_audio_setconfig() or bta_av_co_video_setconfig. +** Parameter err_code is set to an AVDTP status value; +** AVDT_SUCCESS if the codec configuration is ok, +** otherwise error. +** +** Returns void +** +*******************************************************************************/ +void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, UINT8 category, + UINT8 num_seid, UINT8 *p_seid, BOOLEAN recfg_needed, UINT8 avdt_handle) +{ + tBTA_AV_CI_SETCONFIG *p_buf; + + if ((p_buf = (tBTA_AV_CI_SETCONFIG *) GKI_getbuf(sizeof(tBTA_AV_CI_SETCONFIG))) != NULL) { + p_buf->hdr.layer_specific = hndl; + p_buf->hdr.event = (err_code == AVDT_SUCCESS) ? + BTA_AV_CI_SETCONFIG_OK_EVT : BTA_AV_CI_SETCONFIG_FAIL_EVT; + p_buf->err_code = err_code; + p_buf->category = category; + p_buf->recfg_needed = recfg_needed; + p_buf->num_seid = num_seid; + p_buf->avdt_handle = avdt_handle; + if (p_seid && num_seid) { + p_buf->p_seid = (UINT8 *)(p_buf + 1); + memcpy(p_buf->p_seid, p_seid, num_seid); + } else { + p_buf->p_seid = NULL; + p_buf->num_seid = 0; + } + + bta_sys_sendmsg(p_buf); + } +} + +#endif /* #if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/av/bta_av_int.h b/components/bt/bluedroid/bta/av/bta_av_int.h new file mode 100644 index 0000000000..b4fd9755df --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_int.h @@ -0,0 +1,704 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the private interface file for the BTA advanced audio/video. + * + ******************************************************************************/ +#ifndef BTA_AV_INT_H +#define BTA_AV_INT_H + +#include "bta_sys.h" +#include "bta_api.h" +#include "bta_av_api.h" +#include "avdt_api.h" +#include "bta_av_co.h" +#include "list.h" + +#define BTA_AV_DEBUG TRUE +/***************************************************************************** +** Constants +*****************************************************************************/ + +enum { + /* these events are handled by the AV main state machine */ + BTA_AV_API_DISABLE_EVT = BTA_SYS_EVT_START(BTA_ID_AV), + BTA_AV_API_REMOTE_CMD_EVT, + BTA_AV_API_VENDOR_CMD_EVT, + BTA_AV_API_VENDOR_RSP_EVT, + BTA_AV_API_META_RSP_EVT, + BTA_AV_API_RC_CLOSE_EVT, + BTA_AV_AVRC_OPEN_EVT, + BTA_AV_AVRC_MSG_EVT, + BTA_AV_AVRC_NONE_EVT, + + /* these events are handled by the AV stream state machine */ + BTA_AV_API_OPEN_EVT, + BTA_AV_API_CLOSE_EVT, + BTA_AV_AP_START_EVT, /* the following 2 events must be in the same order as the *API_*EVT */ + BTA_AV_AP_STOP_EVT, + BTA_AV_API_RECONFIG_EVT, + BTA_AV_API_PROTECT_REQ_EVT, + BTA_AV_API_PROTECT_RSP_EVT, + BTA_AV_API_RC_OPEN_EVT, + BTA_AV_SRC_DATA_READY_EVT, + BTA_AV_CI_SETCONFIG_OK_EVT, + BTA_AV_CI_SETCONFIG_FAIL_EVT, + BTA_AV_SDP_DISC_OK_EVT, + BTA_AV_SDP_DISC_FAIL_EVT, + BTA_AV_STR_DISC_OK_EVT, + BTA_AV_STR_DISC_FAIL_EVT, + BTA_AV_STR_GETCAP_OK_EVT, + BTA_AV_STR_GETCAP_FAIL_EVT, + BTA_AV_STR_OPEN_OK_EVT, + BTA_AV_STR_OPEN_FAIL_EVT, + BTA_AV_STR_START_OK_EVT, + BTA_AV_STR_START_FAIL_EVT, + BTA_AV_STR_CLOSE_EVT, + BTA_AV_STR_CONFIG_IND_EVT, + BTA_AV_STR_SECURITY_IND_EVT, + BTA_AV_STR_SECURITY_CFM_EVT, + BTA_AV_STR_WRITE_CFM_EVT, + BTA_AV_STR_SUSPEND_CFM_EVT, + BTA_AV_STR_RECONFIG_CFM_EVT, + BTA_AV_AVRC_TIMER_EVT, + BTA_AV_AVDT_CONNECT_EVT, + BTA_AV_AVDT_DISCONNECT_EVT, + BTA_AV_ROLE_CHANGE_EVT, + BTA_AV_AVDT_DELAY_RPT_EVT, + BTA_AV_ACP_CONNECT_EVT, + + /* these events are handled outside of the state machine */ + BTA_AV_API_ENABLE_EVT, + BTA_AV_API_REGISTER_EVT, + BTA_AV_API_DEREGISTER_EVT, + BTA_AV_API_DISCONNECT_EVT, + BTA_AV_CI_SRC_DATA_READY_EVT, + BTA_AV_SIG_CHG_EVT, + BTA_AV_SIG_TIMER_EVT, + BTA_AV_SDP_AVRC_DISC_EVT, + BTA_AV_AVRC_CLOSE_EVT, + BTA_AV_CONN_CHG_EVT, + BTA_AV_DEREG_COMP_EVT, +#if (BTA_AV_SINK_INCLUDED == TRUE) + BTA_AV_API_SINK_ENABLE_EVT, +#endif +#if (AVDT_REPORTING == TRUE) + BTA_AV_AVDT_RPT_CONN_EVT, +#endif + BTA_AV_API_START_EVT, /* the following 2 events must be in the same order as the *AP_*EVT */ + BTA_AV_API_STOP_EVT +}; + +/* events for AV control block state machine */ +#define BTA_AV_FIRST_SM_EVT BTA_AV_API_DISABLE_EVT +#define BTA_AV_LAST_SM_EVT BTA_AV_AVRC_NONE_EVT + +/* events for AV stream control block state machine */ +#define BTA_AV_FIRST_SSM_EVT BTA_AV_API_OPEN_EVT + +/* events that do not go through state machine */ +#define BTA_AV_FIRST_NSM_EVT BTA_AV_API_ENABLE_EVT +#define BTA_AV_LAST_NSM_EVT BTA_AV_API_STOP_EVT + +/* API events passed to both SSMs (by bta_av_api_to_ssm) */ +#define BTA_AV_FIRST_A2S_API_EVT BTA_AV_API_START_EVT +#define BTA_AV_FIRST_A2S_SSM_EVT BTA_AV_AP_START_EVT + +#define BTA_AV_LAST_EVT BTA_AV_API_STOP_EVT + +/* maximum number of SEPS in stream discovery results */ +#define BTA_AV_NUM_SEPS 32 + +/* initialization value for AVRC handle */ +#define BTA_AV_RC_HANDLE_NONE 0xFF + +/* size of database for service discovery */ +#define BTA_AV_DISC_BUF_SIZE 1000 + +/* offset of media type in codec info byte array */ +#define BTA_AV_MEDIA_TYPE_IDX 1 + +/* maximum length of AVDTP security data */ +#define BTA_AV_SECURITY_MAX_LEN 400 + +/* check number of buffers queued at L2CAP when this amount of buffers are queued to L2CAP */ +#define BTA_AV_QUEUE_DATA_CHK_NUM L2CAP_HIGH_PRI_MIN_XMIT_QUOTA + +/* the number of ACL links with AVDT */ +#define BTA_AV_NUM_LINKS AVDT_NUM_LINKS + +#define BTA_AV_CO_ID_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); } +#define BTA_AV_BE_STREAM_TO_CO_ID(u32, p) {u32 = (((UINT32)(*((p) + 2))) + (((UINT32)(*((p) + 1))) << 8) + (((UINT32)(*(p))) << 16)); (p) += 3;} + +/* these bits are defined for bta_av_cb.multi_av */ +#define BTA_AV_MULTI_AV_SUPPORTED 0x01 +#define BTA_AV_MULTI_AV_IN_USE 0x02 + + +/***************************************************************************** +** Data types +*****************************************************************************/ +#if 0 +/* function types for call-out functions */ +typedef BOOLEAN (*tBTA_AV_CO_INIT) (UINT8 *p_codec_type, UINT8 *p_codec_info, + UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index); +typedef void (*tBTA_AV_CO_DISC_RES) (tBTA_AV_HNDL hndl, UINT8 num_seps, + UINT8 num_snk, UINT8 num_src, BD_ADDR addr, UINT16 uuid_local); +typedef UINT8 (*tBTA_AV_CO_GETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, + UINT8 *p_num_protect, UINT8 *p_protect_info); +typedef void (*tBTA_AV_CO_SETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, + UINT8 num_protect, UINT8 *p_protect_info, + UINT8 t_local_sep, UINT8 avdt_handle); +typedef void (*tBTA_AV_CO_OPEN) (tBTA_AV_HNDL hndl, + tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu); +typedef void (*tBTA_AV_CO_CLOSE) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu); +typedef void (*tBTA_AV_CO_START) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr); +typedef void (*tBTA_AV_CO_STOP) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); +typedef void *(*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type, + UINT32 *p_len, UINT32 *p_timestamp); +typedef void (*tBTA_AV_CO_DELAY) (tBTA_AV_HNDL hndl, UINT16 delay); + +/* the call-out functions for one stream */ +typedef struct { + tBTA_AV_CO_INIT init; + tBTA_AV_CO_DISC_RES disc_res; + tBTA_AV_CO_GETCFG getcfg; + tBTA_AV_CO_SETCFG setcfg; + tBTA_AV_CO_OPEN open; + tBTA_AV_CO_CLOSE close; + tBTA_AV_CO_START start; + tBTA_AV_CO_STOP stop; + tBTA_AV_CO_DATAPATH data; + tBTA_AV_CO_DELAY delay; +} tBTA_AV_CO_FUNCTS; +#endif + +/* data type for BTA_AV_API_ENABLE_EVT */ +typedef struct { + BT_HDR hdr; + tBTA_AV_CBACK *p_cback; + tBTA_AV_FEAT features; + tBTA_SEC sec_mask; +} tBTA_AV_API_ENABLE; + +/* data type for BTA_AV_API_REG_EVT */ +typedef struct { + BT_HDR hdr; + char p_service_name[BTA_SERVICE_NAME_LEN + 1]; + UINT8 app_id; + tBTA_AV_DATA_CBACK *p_app_data_cback; + tBTA_AV_CO_FUNCTS *bta_av_cos; +} tBTA_AV_API_REG; + + +enum { + BTA_AV_RS_NONE, /* straight API call */ + BTA_AV_RS_OK, /* the role switch result - successful */ + BTA_AV_RS_FAIL, /* the role switch result - failed */ + BTA_AV_RS_DONE /* the role switch is done - continue */ +}; +typedef UINT8 tBTA_AV_RS_RES; +/* data type for BTA_AV_API_OPEN_EVT */ +typedef struct { + BT_HDR hdr; + BD_ADDR bd_addr; + BOOLEAN use_rc; + tBTA_SEC sec_mask; + tBTA_AV_RS_RES switch_res; + UINT16 uuid; /* uuid of initiator */ +} tBTA_AV_API_OPEN; + +/* data type for BTA_AV_API_STOP_EVT */ +typedef struct { + BT_HDR hdr; + BOOLEAN suspend; + BOOLEAN flush; +} tBTA_AV_API_STOP; + +/* data type for BTA_AV_API_DISCONNECT_EVT */ +typedef struct { + BT_HDR hdr; + BD_ADDR bd_addr; +} tBTA_AV_API_DISCNT; + +/* data type for BTA_AV_API_PROTECT_REQ_EVT */ +typedef struct { + BT_HDR hdr; + UINT8 *p_data; + UINT16 len; +} tBTA_AV_API_PROTECT_REQ; + +/* data type for BTA_AV_API_PROTECT_RSP_EVT */ +typedef struct { + BT_HDR hdr; + UINT8 *p_data; + UINT16 len; + UINT8 error_code; +} tBTA_AV_API_PROTECT_RSP; + +/* data type for BTA_AV_API_REMOTE_CMD_EVT */ +typedef struct { + BT_HDR hdr; + tAVRC_MSG_PASS msg; + UINT8 label; +} tBTA_AV_API_REMOTE_CMD; + +/* data type for BTA_AV_API_VENDOR_CMD_EVT and RSP */ +typedef struct { + BT_HDR hdr; + tAVRC_MSG_VENDOR msg; + UINT8 label; +} tBTA_AV_API_VENDOR; + +/* data type for BTA_AV_API_RC_OPEN_EVT */ +typedef struct { + BT_HDR hdr; +} tBTA_AV_API_OPEN_RC; + +/* data type for BTA_AV_API_RC_CLOSE_EVT */ +typedef struct { + BT_HDR hdr; +} tBTA_AV_API_CLOSE_RC; + +/* data type for BTA_AV_API_META_RSP_EVT */ +typedef struct { + BT_HDR hdr; + BOOLEAN is_rsp; + UINT8 label; + tBTA_AV_CODE rsp_code; + BT_HDR *p_pkt; +} tBTA_AV_API_META_RSP; + + +/* data type for BTA_AV_API_RECONFIG_EVT */ +typedef struct { + BT_HDR hdr; + UINT8 codec_info[AVDT_CODEC_SIZE]; /* codec configuration */ + UINT8 *p_protect_info; + UINT8 num_protect; + BOOLEAN suspend; + UINT8 sep_info_idx; +} tBTA_AV_API_RCFG; + +/* data type for BTA_AV_CI_SETCONFIG_OK_EVT and BTA_AV_CI_SETCONFIG_FAIL_EVT */ +typedef struct { + BT_HDR hdr; + tBTA_AV_HNDL hndl; + UINT8 err_code; + UINT8 category; + UINT8 num_seid; + UINT8 *p_seid; + BOOLEAN recfg_needed; + UINT8 avdt_handle; /* local sep type for which this stream will be set up */ +} tBTA_AV_CI_SETCONFIG; + +/* data type for all stream events from AVDTP */ +typedef struct { + BT_HDR hdr; + tAVDT_CFG cfg; /* configuration/capabilities parameters */ + tAVDT_CTRL msg; /* AVDTP callback message parameters */ + BD_ADDR bd_addr; /* bd address */ + UINT8 handle; + UINT8 avdt_event; + BOOLEAN initiator; /* TRUE, if local device initiates the SUSPEND */ +} tBTA_AV_STR_MSG; + +/* data type for BTA_AV_AVRC_MSG_EVT */ +typedef struct { + BT_HDR hdr; + tAVRC_MSG msg; + UINT8 handle; + UINT8 label; + UINT8 opcode; +} tBTA_AV_RC_MSG; + +/* data type for BTA_AV_AVRC_OPEN_EVT, BTA_AV_AVRC_CLOSE_EVT */ +typedef struct { + BT_HDR hdr; + BD_ADDR peer_addr; + UINT8 handle; +} tBTA_AV_RC_CONN_CHG; + +/* data type for BTA_AV_CONN_CHG_EVT */ +typedef struct { + BT_HDR hdr; + BD_ADDR peer_addr; + BOOLEAN is_up; +} tBTA_AV_CONN_CHG; + +/* data type for BTA_AV_ROLE_CHANGE_EVT */ +typedef struct { + BT_HDR hdr; + UINT8 new_role; + UINT8 hci_status; +} tBTA_AV_ROLE_RES; + +/* data type for BTA_AV_SDP_DISC_OK_EVT */ +typedef struct { + BT_HDR hdr; + UINT16 avdt_version; /* AVDTP protocol version */ +} tBTA_AV_SDP_RES; + +/* type for SEP control block */ +typedef struct { + UINT8 av_handle; /* AVDTP handle */ + tBTA_AV_CODEC codec_type; /* codec type */ + UINT8 tsep; /* SEP type of local SEP */ + tBTA_AV_DATA_CBACK *p_app_data_cback; /* Application callback for media packets */ +} tBTA_AV_SEP; + + +/* initiator/acceptor role for adaption */ +#define BTA_AV_ROLE_AD_INT 0x00 /* initiator */ +#define BTA_AV_ROLE_AD_ACP 0x01 /* acceptor */ + +/* initiator/acceptor signaling roles */ +#define BTA_AV_ROLE_START_ACP 0x00 +#define BTA_AV_ROLE_START_INT 0x10 /* do not change this value */ + +#define BTA_AV_ROLE_SUSPEND 0x20 /* suspending on start */ +#define BTA_AV_ROLE_SUSPEND_OPT 0x40 /* Suspend on Start option is set */ + +/* union of all event datatypes */ +typedef union { + BT_HDR hdr; + tBTA_AV_API_ENABLE api_enable; + tBTA_AV_API_REG api_reg; + tBTA_AV_API_OPEN api_open; + tBTA_AV_API_STOP api_stop; + tBTA_AV_API_DISCNT api_discnt; + tBTA_AV_API_PROTECT_REQ api_protect_req; + tBTA_AV_API_PROTECT_RSP api_protect_rsp; + tBTA_AV_API_REMOTE_CMD api_remote_cmd; + tBTA_AV_API_VENDOR api_vendor; + tBTA_AV_API_RCFG api_reconfig; + tBTA_AV_CI_SETCONFIG ci_setconfig; + tBTA_AV_STR_MSG str_msg; + tBTA_AV_RC_MSG rc_msg; + tBTA_AV_RC_CONN_CHG rc_conn_chg; + tBTA_AV_CONN_CHG conn_chg; + tBTA_AV_ROLE_RES role_res; + tBTA_AV_SDP_RES sdp_res; + tBTA_AV_API_META_RSP api_meta_rsp; +} tBTA_AV_DATA; + +typedef void (tBTA_AV_VDP_DATA_ACT)(void *p_scb); + +typedef struct { + tBTA_AV_VDP_DATA_ACT *p_act; + UINT8 *p_frame; + UINT16 buf_size; + UINT32 len; + UINT32 offset; + UINT32 timestamp; +} tBTA_AV_VF_INFO; + +typedef union { + tBTA_AV_VF_INFO vdp; /* used for video channels only */ + tBTA_AV_API_OPEN open; /* used only before open and role switch + is needed on another AV channel */ +} tBTA_AV_Q_INFO; + +#define BTA_AV_Q_TAG_OPEN 0x01 /* after API_OPEN, before STR_OPENED */ +#define BTA_AV_Q_TAG_START 0x02 /* before start sending media packets */ +#define BTA_AV_Q_TAG_STREAM 0x03 /* during streaming */ + +#define BTA_AV_WAIT_ACP_CAPS_ON 0x01 /* retriving the peer capabilities */ +#define BTA_AV_WAIT_ACP_CAPS_STARTED 0x02 /* started while retriving peer capabilities */ +#define BTA_AV_WAIT_ROLE_SW_RES_OPEN 0x04 /* waiting for role switch result after API_OPEN, before STR_OPENED */ +#define BTA_AV_WAIT_ROLE_SW_RES_START 0x08 /* waiting for role switch result before streaming */ +#define BTA_AV_WAIT_ROLE_SW_STARTED 0x10 /* started while waiting for role switch result */ +#define BTA_AV_WAIT_ROLE_SW_RETRY 0x20 /* set when retry on timeout */ +#define BTA_AV_WAIT_CHECK_RC 0x40 /* set when the timer is used by role switch */ +#define BTA_AV_WAIT_ROLE_SW_FAILED 0x80 /* role switch failed */ + +#define BTA_AV_WAIT_ROLE_SW_BITS (BTA_AV_WAIT_ROLE_SW_RES_OPEN|BTA_AV_WAIT_ROLE_SW_RES_START|BTA_AV_WAIT_ROLE_SW_STARTED|BTA_AV_WAIT_ROLE_SW_RETRY) + +/* Bitmap for collision, coll_mask */ +#define BTA_AV_COLL_INC_TMR 0x01 /* Timer is running for incoming L2C connection */ +#define BTA_AV_COLL_API_CALLED 0x02 /* API open was called while incoming timer is running */ + +/* type for AV stream control block */ +typedef struct { + const tBTA_AV_ACT *p_act_tbl; /* the action table for stream state machine */ + const tBTA_AV_CO_FUNCTS *p_cos; /* the associated callout functions */ + tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */ + tBTA_AV_SEP seps[BTA_AV_MAX_SEPS]; + tAVDT_CFG *p_cap; /* buffer used for get capabilities */ + list_t *a2d_list; /* used for audio channels only */ + tBTA_AV_Q_INFO q_info; + tAVDT_SEP_INFO sep_info[BTA_AV_NUM_SEPS]; /* stream discovery results */ + tAVDT_CFG cfg; /* local SEP configuration */ + TIMER_LIST_ENT timer; /* delay timer for AVRC CT */ + BD_ADDR peer_addr; /* peer BD address */ + UINT16 l2c_cid; /* L2CAP channel ID */ + UINT16 stream_mtu; /* MTU of stream */ + UINT16 avdt_version; /* the avdt version of peer device */ + tBTA_SEC sec_mask; /* security mask */ + tBTA_AV_CODEC codec_type; /* codec type */ + UINT8 media_type; /* Media type */ + BOOLEAN cong; /* TRUE if AVDTP congested */ + tBTA_AV_STATUS open_status; /* open failure status */ + tBTA_AV_CHNL chnl; /* the channel: audio/video */ + tBTA_AV_HNDL hndl; /* the handle: ((hdi + 1)|chnl) */ + UINT16 cur_psc_mask; /* Protocol service capabilities mask for current connection */ + UINT8 avdt_handle; /* AVDTP handle */ + UINT8 hdi; /* the index to SCB[] */ + UINT8 num_seps; /* number of seps returned by stream discovery */ + UINT8 num_disc_snks; /* number of discovered snks */ + UINT8 num_disc_srcs; /* number of discovered srcs */ + UINT8 sep_info_idx; /* current index into sep_info */ + UINT8 sep_idx; /* current index into local seps[] */ + UINT8 rcfg_idx; /* reconfig requested index into sep_info */ + UINT8 state; /* state machine state */ + UINT8 avdt_label; /* AVDTP label */ + UINT8 app_id; /* application id */ + UINT8 num_recfg; /* number of reconfigure sent */ + UINT8 role; + UINT8 l2c_bufs; /* the number of buffers queued to L2CAP */ + UINT8 rc_handle; /* connected AVRCP handle */ + BOOLEAN use_rc; /* TRUE if AVRCP is allowed */ + BOOLEAN started; /* TRUE if stream started */ + UINT8 co_started; /* non-zero, if stream started from call-out perspective */ + BOOLEAN recfg_sup; /* TRUE if the first attempt to reconfigure the stream was successfull, else False if command fails */ + BOOLEAN suspend_sup; /* TRUE if Suspend stream is supported, else FALSE if suspend command fails */ + BOOLEAN deregistring; /* TRUE if deregistering */ + BOOLEAN sco_suspend; /* TRUE if SUSPEND is issued automatically for SCO */ + UINT8 coll_mask; /* Mask to check incoming and outgoing collision */ + tBTA_AV_API_OPEN open_api; /* Saved OPEN api message */ + UINT8 wait; /* set 0x1, when getting Caps as ACP, set 0x2, when started */ + UINT8 q_tag; /* identify the associated q_info union member */ + BOOLEAN no_rtp_hdr; /* TRUE if add no RTP header*/ + UINT8 disc_rsn; /* disconenction reason */ + UINT16 uuid_int; /*intended UUID of Initiator to connect to */ +} tBTA_AV_SCB; + +#define BTA_AV_RC_ROLE_MASK 0x10 +#define BTA_AV_RC_ROLE_INT 0x00 +#define BTA_AV_RC_ROLE_ACP 0x10 + +#define BTA_AV_RC_CONN_MASK 0x20 + +/* type for AV RCP control block */ +/* index to this control block is the rc handle */ +typedef struct { + UINT8 status; + UINT8 handle; + UINT8 shdl; /* stream handle (hdi + 1) */ + UINT8 lidx; /* (index+1) to LCB */ + tBTA_AV_FEAT peer_features; /* peer features mask */ +} tBTA_AV_RCB; +#define BTA_AV_NUM_RCB (BTA_AV_NUM_STRS + 2) + +enum { + BTA_AV_LCB_FREE, + BTA_AV_LCB_FIND +}; + +/* type for AV ACL Link control block */ +typedef struct { + BD_ADDR addr; /* peer BD address */ + UINT8 conn_msk; /* handle mask of connected stream handle */ + UINT8 lidx; /* index + 1 */ +} tBTA_AV_LCB; + +/* type for stream state machine action functions */ +typedef void (*tBTA_AV_SACT)(tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); + + +/* type for AV control block */ +typedef struct { + tBTA_AV_SCB *p_scb[BTA_AV_NUM_STRS]; /* stream control block */ + tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */ + tBTA_AV_CBACK *p_cback; /* application callback function */ + tBTA_AV_RCB rcb[BTA_AV_NUM_RCB]; /* RCB control block */ + tBTA_AV_LCB lcb[BTA_AV_NUM_LINKS + 1]; /* link control block */ + TIMER_LIST_ENT sig_tmr; /* link timer */ + TIMER_LIST_ENT acp_sig_tmr; /* timer to monitor signalling when accepting */ + UINT32 sdp_a2d_handle; /* SDP record handle for audio src */ +#if (BTA_AV_SINK_INCLUDED == TRUE) + UINT32 sdp_a2d_snk_handle; /* SDP record handle for audio snk */ +#endif + UINT32 sdp_vdp_handle; /* SDP record handle for video src */ + tBTA_AV_FEAT features; /* features mask */ + tBTA_SEC sec_mask; /* security mask */ + tBTA_AV_HNDL handle; /* the handle for SDP activity */ + BOOLEAN disabling; /* TRUE if api disabled called */ + UINT8 disc; /* (hdi+1) or (rc_handle|BTA_AV_CHNL_MSK) if p_disc_db is in use */ + UINT8 state; /* state machine state */ + UINT8 conn_rc; /* handle mask of connected RCP channels */ + UINT8 conn_audio; /* handle mask of connected audio channels */ + UINT8 conn_video; /* handle mask of connected video channels */ + UINT8 conn_lcb; /* index mask of used LCBs */ + UINT8 audio_open_cnt; /* number of connected audio channels */ + UINT8 reg_audio; /* handle mask of registered audio channels */ + UINT8 reg_video; /* handle mask of registered video channels */ + UINT8 rc_acp_handle; + UINT8 rc_acp_idx; /* (index + 1) to RCB */ + UINT8 rs_idx; /* (index + 1) to SCB for the one waiting for RS on open */ + BOOLEAN sco_occupied; /* TRUE if SCO is being used or call is in progress */ + UINT8 audio_streams; /* handle mask of streaming audio channels */ + UINT8 video_streams; /* handle mask of streaming video channels */ +} tBTA_AV_CB; + + + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* control block declaration */ +#if BTA_DYNAMIC_MEMORY == FALSE +extern tBTA_AV_CB bta_av_cb; +#else +extern tBTA_AV_CB *bta_av_cb_ptr; +#define bta_av_cb (*bta_av_cb_ptr) +#endif + +/* config struct */ +extern tBTA_AV_CFG *p_bta_av_cfg; + +/* rc id config struct */ +extern UINT16 *p_bta_av_rc_id; +extern UINT16 *p_bta_av_rc_id_ac; + +extern const tBTA_AV_SACT bta_av_a2d_action[]; +// extern const tBTA_AV_CO_FUNCTS bta_av_a2d_cos; +extern const tBTA_AV_SACT bta_av_vdp_action[]; +extern tAVDT_CTRL_CBACK *const bta_av_dt_cback[]; +extern void bta_av_stream_data_cback(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt); + +/***************************************************************************** +** Function prototypes +*****************************************************************************/ +/* utility functions */ +extern tBTA_AV_SCB *bta_av_hndl_to_scb(UINT16 handle); +extern BOOLEAN bta_av_chk_start(tBTA_AV_SCB *p_scb); +extern void bta_av_restore_switch (void); +extern UINT16 bta_av_chk_mtu(tBTA_AV_SCB *p_scb, UINT16 mtu); +extern void bta_av_conn_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data); +extern UINT8 bta_av_rc_create(tBTA_AV_CB *p_cb, UINT8 role, UINT8 shdl, UINT8 lidx); +extern void bta_av_stream_chg(tBTA_AV_SCB *p_scb, BOOLEAN started); +extern BOOLEAN bta_av_is_scb_opening (tBTA_AV_SCB *p_scb); +extern BOOLEAN bta_av_is_scb_incoming (tBTA_AV_SCB *p_scb); +extern void bta_av_set_scb_sst_init (tBTA_AV_SCB *p_scb); +extern BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb); +extern void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb); +extern tBTA_AV_LCB *bta_av_find_lcb(BD_ADDR addr, UINT8 op); + + +/* main functions */ +extern void bta_av_api_deregister(tBTA_AV_DATA *p_data); +extern void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf); +extern void bta_av_sm_execute(tBTA_AV_CB *p_cb, UINT16 event, tBTA_AV_DATA *p_data); +extern void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data); +extern BOOLEAN bta_av_hdl_event(BT_HDR *p_msg); +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +extern char *bta_av_evt_code(UINT16 evt_code); +#endif +extern BOOLEAN bta_av_switch_if_needed(tBTA_AV_SCB *p_scb); +extern BOOLEAN bta_av_link_role_ok(tBTA_AV_SCB *p_scb, UINT8 bits); +extern BOOLEAN bta_av_is_rcfg_sst(tBTA_AV_SCB *p_scb); + +/* nsm action functions */ +extern void bta_av_api_disconnect(tBTA_AV_DATA *p_data); +extern void bta_av_sig_chg(tBTA_AV_DATA *p_data); +extern void bta_av_sig_timer(tBTA_AV_DATA *p_data); +extern void bta_av_rc_disc_done(tBTA_AV_DATA *p_data); +extern void bta_av_rc_closed(tBTA_AV_DATA *p_data); +extern void bta_av_rc_disc(UINT8 disc); +extern void bta_av_conn_chg(tBTA_AV_DATA *p_data); +extern void bta_av_dereg_comp(tBTA_AV_DATA *p_data); + +/* sm action functions */ +extern void bta_av_disable (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_opened (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_remote_cmd (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_vendor_cmd (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_vendor_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_close (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_meta_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_free_rsp (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); +extern void bta_av_rc_free_msg (tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); + +extern tBTA_AV_RCB *bta_av_get_rcb_by_shdl(UINT8 shdl); +extern void bta_av_del_rc(tBTA_AV_RCB *p_rcb); + +/* ssm action functions */ +extern void bta_av_do_disc_a2d (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_cleanup (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_free_sdb (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_config_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_disconnect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_setconfig_rsp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_ind (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_do_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_connect_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_sdp_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_disc_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_disc_res_as_acp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_open_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_discover_req (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_conn_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_do_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_str_stopped (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_reconfig (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_data_path (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_start_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_start_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_str_closed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_clr_cong (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_suspend_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_str_ok (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_failed (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_connect (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_discntd (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_suspend_cont (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_cfm (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rcfg_open (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_security_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_open_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_chk_2nd_start (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_save_caps (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rej_conn (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_rej_conn (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_set_use_rc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_cco_close (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_switch_role (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_role_res (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_delay_co (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_open_at_inc (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); + +/* ssm action functions - vdp specific */ +extern void bta_av_do_disc_vdp (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_vdp_str_opened (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data); +extern void bta_av_reg_vdp (tAVDT_CS *p_cs, char *p_service_name, void *p_data); + +#endif /* BTA_AV_INT_H */ diff --git a/components/bt/bluedroid/bta/av/bta_av_main.c b/components/bt/bluedroid/bta/av/bta_av_main.c new file mode 100644 index 0000000000..1d844775c7 --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_main.c @@ -0,0 +1,1351 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the main implementation file for the BTA advanced audio/video. + * + ******************************************************************************/ + +// #include +#include + +#include "bt_target.h" +// #include "osi/include/log.h" +#include "bt_trace.h" + +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) +#include "bta_av_int.h" +#include "utl.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#include "bta_av_co.h" +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#include "bta_ar_api.h" +#endif +#include "osi.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* AVDTP protocol timeout values */ +#define BTIF_AVK_SERVICE_NAME "Advanced Audio Sink" + +#ifndef BTA_AV_RET_TOUT +#define BTA_AV_RET_TOUT 4 +#endif + +#ifndef BTA_AV_SIG_TOUT +#define BTA_AV_SIG_TOUT 4 +#endif + +#ifndef BTA_AV_IDLE_TOUT +#define BTA_AV_IDLE_TOUT 10 +#endif + +/* the delay time in milliseconds to retry role switch */ +#ifndef BTA_AV_RS_TIME_VAL +#define BTA_AV_RS_TIME_VAL 1000 +#endif + +/* state machine states */ +enum { + BTA_AV_INIT_ST, + BTA_AV_OPEN_ST +}; + +/* state machine action enumeration list */ +enum { + BTA_AV_DISABLE, + BTA_AV_RC_OPENED, + BTA_AV_RC_REMOTE_CMD, + BTA_AV_RC_VENDOR_CMD, + BTA_AV_RC_VENDOR_RSP, + BTA_AV_RC_FREE_RSP, + BTA_AV_RC_FREE_MSG, + BTA_AV_RC_META_RSP, + BTA_AV_RC_MSG, + BTA_AV_RC_CLOSE, + BTA_AV_NUM_ACTIONS +}; + +#define BTA_AV_IGNORE BTA_AV_NUM_ACTIONS + +/* type for action functions */ +typedef void (*tBTA_AV_ACTION)(tBTA_AV_CB *p_cb, tBTA_AV_DATA *p_data); + +/* action functions */ +const tBTA_AV_ACTION bta_av_action[] = { + bta_av_disable, + bta_av_rc_opened, + bta_av_rc_remote_cmd, + bta_av_rc_vendor_cmd, + bta_av_rc_vendor_rsp, + bta_av_rc_free_rsp, + bta_av_rc_free_msg, + bta_av_rc_meta_rsp, + bta_av_rc_msg, + bta_av_rc_close, + NULL +}; + +/* state table information */ +#define BTA_AV_ACTION_COL 0 /* position of actions */ +#define BTA_AV_NEXT_STATE 1 /* position of next state */ +#define BTA_AV_NUM_COLS 2 /* number of columns in state tables */ + +/* state table for init state */ +static const UINT8 bta_av_st_init[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Next state */ + /* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST }, + /* API_REMOTE_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, + /* API_VENDOR_CMD_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, + /* API_VENDOR_RSP_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, + /* API_META_RSP_EVT */ {BTA_AV_RC_FREE_RSP, BTA_AV_INIT_ST }, + /* API_RC_CLOSE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, + /* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST }, + /* AVRC_MSG_EVT */ {BTA_AV_RC_FREE_MSG, BTA_AV_INIT_ST }, + /* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +}; + +/* state table for open state */ +static const UINT8 bta_av_st_open[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Next state */ + /* API_DISABLE_EVT */ {BTA_AV_DISABLE, BTA_AV_INIT_ST }, + /* API_REMOTE_CMD_EVT */ {BTA_AV_RC_REMOTE_CMD, BTA_AV_OPEN_ST }, + /* API_VENDOR_CMD_EVT */ {BTA_AV_RC_VENDOR_CMD, BTA_AV_OPEN_ST }, + /* API_VENDOR_RSP_EVT */ {BTA_AV_RC_VENDOR_RSP, BTA_AV_OPEN_ST }, + /* API_META_RSP_EVT */ {BTA_AV_RC_META_RSP, BTA_AV_OPEN_ST }, + /* API_RC_CLOSE_EVT */ {BTA_AV_RC_CLOSE, BTA_AV_OPEN_ST }, + /* AVRC_OPEN_EVT */ {BTA_AV_RC_OPENED, BTA_AV_OPEN_ST }, + /* AVRC_MSG_EVT */ {BTA_AV_RC_MSG, BTA_AV_OPEN_ST }, + /* AVRC_NONE_EVT */ {BTA_AV_IGNORE, BTA_AV_INIT_ST }, +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_AV_ST_TBL)[BTA_AV_NUM_COLS]; + +/* state table */ +static const tBTA_AV_ST_TBL bta_av_st_tbl[] = { + bta_av_st_init, + bta_av_st_open +}; + +typedef void (*tBTA_AV_NSM_ACT)(tBTA_AV_DATA *p_data); +static void bta_av_api_enable(tBTA_AV_DATA *p_data); +static void bta_av_api_register(tBTA_AV_DATA *p_data); +#if (BTA_AV_SINK_INCLUDED == TRUE) +static void bta_av_api_sink_enable(tBTA_AV_DATA *p_data); +#endif +static void bta_av_ci_data(tBTA_AV_DATA *p_data); +#if (AVDT_REPORTING == TRUE) +static void bta_av_rpc_conn(tBTA_AV_DATA *p_data); +#endif +static void bta_av_api_to_ssm(tBTA_AV_DATA *p_data); + +static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 + app_id, BD_ADDR peer_addr); +static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); + + +/* action functions */ +const tBTA_AV_NSM_ACT bta_av_nsm_act[] = { + bta_av_api_enable, /* BTA_AV_API_ENABLE_EVT */ + bta_av_api_register, /* BTA_AV_API_REGISTER_EVT */ + bta_av_api_deregister, /* BTA_AV_API_DEREGISTER_EVT */ + bta_av_api_disconnect, /* BTA_AV_API_DISCONNECT_EVT */ + bta_av_ci_data, /* BTA_AV_CI_SRC_DATA_READY_EVT */ + bta_av_sig_chg, /* BTA_AV_SIG_CHG_EVT */ + bta_av_sig_timer, /* BTA_AV_SIG_TIMER_EVT */ + bta_av_rc_disc_done, /* BTA_AV_SDP_AVRC_DISC_EVT */ + bta_av_rc_closed, /* BTA_AV_AVRC_CLOSE_EVT */ + bta_av_conn_chg, /* BTA_AV_CONN_CHG_EVT */ + bta_av_dereg_comp, /* BTA_AV_DEREG_COMP_EVT */ +#if (BTA_AV_SINK_INCLUDED == TRUE) + bta_av_api_sink_enable, /* BTA_AV_API_SINK_ENABLE_EVT */ +#endif +#if (AVDT_REPORTING == TRUE) + bta_av_rpc_conn, /* BTA_AV_AVDT_RPT_CONN_EVT */ +#endif + bta_av_api_to_ssm, /* BTA_AV_API_START_EVT */ + bta_av_api_to_ssm, /* BTA_AV_API_STOP_EVT */ +}; + +/***************************************************************************** +** Global data +*****************************************************************************/ + +/* AV control block */ +#if BTA_DYNAMIC_MEMORY == FALSE +tBTA_AV_CB bta_av_cb; +#endif + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +static char *bta_av_st_code(UINT8 state); +#endif + +/******************************************************************************* +** +** Function bta_av_timer_cback +** +** Description forward the event to stream state machine +** +** Returns void +** +*******************************************************************************/ +static void bta_av_timer_cback(void *p_tle) +{ + BT_HDR *p_buf; + TIMER_LIST_ENT *p = (TIMER_LIST_ENT *)p_tle; + int xx; + tBTA_AV_SCB *p_scb = NULL; + + /* find the SCB that has the timer */ + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + if (bta_av_cb.p_scb[xx] && &(bta_av_cb.p_scb[xx]->timer) == p) { + p_scb = bta_av_cb.p_scb[xx]; + break; + } + } + + if (p_scb && (p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { + /* send the event through the audio state machine. + * only when the audio SM is open, the main SM opens the RC connection as INT */ + p_buf->event = p->event; + p_buf->layer_specific = p_scb->hndl; + bta_sys_sendmsg(p_buf); + } +} + +/******************************************************************************* +** +** Function bta_av_api_enable +** +** Description Handle an API enable event. +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_api_enable(tBTA_AV_DATA *p_data) +{ + int i; + tBTA_AV_ENABLE enable; + + /* initialize control block */ + memset(&bta_av_cb, 0, sizeof(tBTA_AV_CB)); + + for (i = 0; i < BTA_AV_NUM_RCB; i++) { + bta_av_cb.rcb[i].handle = BTA_AV_RC_HANDLE_NONE; + } + + bta_av_cb.rc_acp_handle = BTA_AV_RC_HANDLE_NONE; + + /* store parameters */ + bta_av_cb.p_cback = p_data->api_enable.p_cback; + bta_av_cb.features = p_data->api_enable.features; + bta_av_cb.sec_mask = p_data->api_enable.sec_mask; + + enable.features = bta_av_cb.features; + + /* Register for SCO change event */ + if (!(bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD)) { + bta_sys_sco_register(bta_av_sco_chg_cback); + } + + /* call callback with enable event */ + (*bta_av_cb.p_cback)(BTA_AV_ENABLE_EVT, (tBTA_AV *)&enable); +} + +/******************************************************************************* +** +** Function bta_av_addr_to_scb +** +** Description find the stream control block by the peer addr +** +** Returns void +** +*******************************************************************************/ +static tBTA_AV_SCB *bta_av_addr_to_scb(BD_ADDR bd_addr) +{ + tBTA_AV_SCB *p_scb = NULL; + int xx; + + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + if (bta_av_cb.p_scb[xx]) { + if (!bdcmp(bd_addr, bta_av_cb.p_scb[xx]->peer_addr)) { + p_scb = bta_av_cb.p_scb[xx]; + break; + } + } + } + return p_scb; +} + +/******************************************************************************* +** +** Function bta_av_hndl_to_scb +** +** Description find the stream control block by the handle +** +** Returns void +** +*******************************************************************************/ +tBTA_AV_SCB *bta_av_hndl_to_scb(UINT16 handle) +{ + tBTA_AV_HNDL hndl = (tBTA_AV_HNDL)handle; + tBTA_AV_SCB *p_scb = NULL; + UINT8 idx = (hndl & BTA_AV_HNDL_MSK); + + if (idx && (idx <= BTA_AV_NUM_STRS) ) { + p_scb = bta_av_cb.p_scb[idx - 1]; + } + return p_scb; +} + +/******************************************************************************* +** +** Function bta_av_alloc_scb +** +** Description allocate stream control block, +** register the service to stack +** create SDP record +** +** Returns void +** +*******************************************************************************/ +static tBTA_AV_SCB *bta_av_alloc_scb(tBTA_AV_CHNL chnl) +{ + tBTA_AV_SCB *p_ret = NULL; + int xx; + tBTA_AV_STATUS sts = BTA_AV_SUCCESS; + + if (chnl == BTA_AV_CHNL_VIDEO) { + if (p_bta_av_cfg->p_act_tbl == NULL || p_bta_av_cfg->p_reg == NULL) { + APPL_TRACE_ERROR("Video streaming not supported"); + sts = BTA_AV_FAIL; + } else { + /* allow only one Video channel */ + if (bta_av_cb.reg_video) { + APPL_TRACE_ERROR("Already registered"); + sts = BTA_AV_FAIL; + } + } + } else if (chnl != BTA_AV_CHNL_AUDIO) { + APPL_TRACE_ERROR("bad channel: %d\n", chnl); + sts = BTA_AV_FAIL; + } + + if (sts == BTA_AV_SUCCESS) { + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + if (bta_av_cb.p_scb[xx] == NULL) { + /* found an empty spot */ + p_ret = (tBTA_AV_SCB *)GKI_getbuf(sizeof(tBTA_AV_SCB)); + if (p_ret) { + memset(p_ret, 0, sizeof(tBTA_AV_SCB)); + p_ret->rc_handle = BTA_AV_RC_HANDLE_NONE; + p_ret->chnl = chnl; + p_ret->hndl = (tBTA_AV_HNDL)((xx + 1) | chnl); + p_ret->hdi = xx; + p_ret->a2d_list = list_new(NULL); + bta_av_cb.p_scb[xx] = p_ret; + } + break; + } + } + } + return p_ret; +} + +/******************************************************************************* +** +** Function bta_av_free_scb +** +** Description free stream control block, +** +** +** Returns void +** +*******************************************************************************/ +UNUSED_ATTR static void bta_av_free_scb(tBTA_AV_SCB *p_scb) +{ + // NOTE(google) This free currently is not called + assert(p_scb != NULL); + + list_free(p_scb->a2d_list); + GKI_freebuf(p_scb); +} + +/******************************************************************************* +*******************************************************************************/ +void bta_av_conn_cback(UINT8 handle, BD_ADDR bd_addr, UINT8 event, tAVDT_CTRL *p_data) +{ + tBTA_AV_STR_MSG *p_msg; + UINT16 evt = 0; + tBTA_AV_SCB *p_scb = NULL; + UNUSED(handle); + +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + if (event == BTA_AR_AVDT_CONN_EVT || + event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT) +#else + if (event == AVDT_CONNECT_IND_EVT || event == AVDT_DISCONNECT_IND_EVT) +#endif + { + evt = BTA_AV_SIG_CHG_EVT; + if (AVDT_DISCONNECT_IND_EVT == event) { + p_scb = bta_av_addr_to_scb(bd_addr); + } +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + else if (AVDT_CONNECT_IND_EVT == event) { + APPL_TRACE_DEBUG("CONN_IND is ACP:%d\n", p_data->hdr.err_param); + } +#endif + + if (/*((p_scb && (p_scb->role & BTA_AV_ROLE_AD_ACP)) || + + //(AVDT_CONNECT_IND_EVT == event && AVDT_ACP == p_data->hdr.err_param)) + + (AVDT_CONNECT_IND_EVT == event))&& */ + (p_msg = (tBTA_AV_STR_MSG *) GKI_getbuf((UINT16) (sizeof(tBTA_AV_STR_MSG)))) != NULL) { + p_msg->hdr.event = evt; + p_msg->hdr.layer_specific = event; + p_msg->hdr.offset = p_data->hdr.err_param; + bdcpy(p_msg->bd_addr, bd_addr); +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + if (p_scb) { + APPL_TRACE_DEBUG("scb hndl x%x, role x%x\n", p_scb->hndl, p_scb->role); + } +#endif + APPL_TRACE_DEBUG("conn_cback bd_addr:%02x-%02x-%02x-%02x-%02x-%02x\n", + bd_addr[0], bd_addr[1], + bd_addr[2], bd_addr[3], + bd_addr[4], bd_addr[5]); + bta_sys_sendmsg(p_msg); + } + } + +} + +#if AVDT_REPORTING == TRUE +/******************************************************************************* +** +** Function bta_av_a2dp_report_cback +** +** Description A2DP report callback. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_a2dp_report_cback(UINT8 handle, AVDT_REPORT_TYPE type, + tAVDT_REPORT_DATA *p_data) +{ + UNUSED(handle); + UNUSED(type); + UNUSED(p_data); + /* Do not need to handle report data for now. + * This empty function is here for conformance reasons. */ +} +#endif + +#if (BTA_AV_SINK_INCLUDED == TRUE) +/******************************************************************************* +** +** Function bta_av_api_sink_enable +** +** Description activate, deactive A2DP Sink, +** +** Returns void +** +*******************************************************************************/ + +static void bta_av_api_sink_enable(tBTA_AV_DATA *p_data) +{ + UINT16 activate_sink = 0; + activate_sink = p_data->hdr.layer_specific; + APPL_TRACE_DEBUG("bta_av_api_sink_enable %d \n", activate_sink) + char p_service_name[BTA_SERVICE_NAME_LEN + 1]; + BCM_STRNCPY_S(p_service_name, sizeof(p_service_name), + BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN); + + if (activate_sink) { + AVDT_SINK_Activate(); + if (bta_av_cb.sdp_a2d_snk_handle == 0) { + bta_av_cb.sdp_a2d_snk_handle = SDP_CreateRecord(); + A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_service_name, NULL, + A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_snk_handle); + bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK); + } + } else { + AVDT_SINK_Deactivate(); + if (bta_av_cb.sdp_a2d_snk_handle != 0) { + SDP_DeleteRecord(bta_av_cb.sdp_a2d_snk_handle); + bta_av_cb.sdp_a2d_snk_handle = 0; + bta_sys_remove_uuid(UUID_SERVCLASS_AUDIO_SINK); + } + } +} +#endif +/******************************************************************************* +** +** Function bta_av_api_register +** +** Description allocate stream control block, +** register the service to stack +** create SDP record +** +** Returns void +** +*******************************************************************************/ +static void bta_av_api_register(tBTA_AV_DATA *p_data) +{ + tBTA_AV_REGISTER registr; + tBTA_AV_SCB *p_scb; /* stream control block */ + tAVDT_REG reg; + tAVDT_CS cs; + char *p_service_name; + tBTA_AV_CODEC codec_type; + tBTA_UTL_COD cod; + UINT8 index = 0; + char p_avk_service_name[BTA_SERVICE_NAME_LEN + 1]; + BCM_STRNCPY_S(p_avk_service_name, sizeof(p_avk_service_name), BTIF_AVK_SERVICE_NAME, BTA_SERVICE_NAME_LEN); + + memset(&cs, 0, sizeof(tAVDT_CS)); + + registr.status = BTA_AV_FAIL_RESOURCES; + registr.app_id = p_data->api_reg.app_id; + registr.chnl = (tBTA_AV_CHNL)p_data->hdr.layer_specific; + registr.p_bta_av_cos = p_data->api_reg.bta_av_cos; + do { + p_scb = bta_av_alloc_scb(registr.chnl); + if (p_scb == NULL) { + APPL_TRACE_ERROR("failed to alloc SCB"); + break; + } + + registr.hndl = p_scb->hndl; + p_scb->app_id = registr.app_id; + + /* initialize the stream control block */ + p_scb->timer.p_cback = (TIMER_CBACK *)&bta_av_timer_cback; + registr.status = BTA_AV_SUCCESS; + + if ((bta_av_cb.reg_audio + bta_av_cb.reg_video) == 0) { + /* the first channel registered. register to AVDTP */ + reg.ctrl_mtu = p_bta_av_cfg->sig_mtu; + reg.ret_tout = BTA_AV_RET_TOUT; + reg.sig_tout = BTA_AV_SIG_TOUT; + reg.idle_tout = BTA_AV_IDLE_TOUT; + reg.sec_mask = bta_av_cb.sec_mask; +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + bta_ar_reg_avdt(®, bta_av_conn_cback, BTA_ID_AV); +#endif + bta_sys_role_chg_register(&bta_av_sys_rs_cback); + + /* create remote control TG service if required */ + if (bta_av_cb.features & (BTA_AV_FEAT_RCTG)) { + /* register with no authorization; let AVDTP use authorization instead */ +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE) + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + bta_av_cb.sec_mask, BTA_ID_AV); +#else + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV); +#endif + + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REM_CTRL_TARGET, "AV Remote Control Target\n", NULL, + p_bta_av_cfg->avrc_tg_cat, BTA_ID_AV); +#endif + } + + /* Set the Capturing service class bit */ +#if (BTA_AV_SINK_INCLUDED == TRUE) + cod.service = BTM_COD_SERVICE_CAPTURING | BTM_COD_SERVICE_RENDERING; +#else + cod.service = BTM_COD_SERVICE_CAPTURING; +#endif + utl_set_device_class(&cod, BTA_UTL_SET_COD_SERVICE_CLASS); + } /* if 1st channel */ + + /* get stream configuration and create stream */ + /* memset(&cs.cfg,0,sizeof(tAVDT_CFG)); */ + cs.cfg.num_codec = 1; + cs.tsep = AVDT_TSEP_SRC; + + /* + * memset of cs takes care setting call back pointers to null. + cs.p_data_cback = NULL; + cs.p_report_cback = NULL; + */ + cs.nsc_mask = AVDT_NSC_RECONFIG | + ((bta_av_cb.features & BTA_AV_FEAT_PROTECT) ? 0 : AVDT_NSC_SECURITY); + APPL_TRACE_DEBUG("nsc_mask: 0x%x\n", cs.nsc_mask); + + if (p_data->api_reg.p_service_name[0] == 0) { + p_service_name = NULL; + } else { + p_service_name = p_data->api_reg.p_service_name; + } + + p_scb->suspend_sup = TRUE; + p_scb->recfg_sup = TRUE; + + cs.p_ctrl_cback = bta_av_dt_cback[p_scb->hdi]; + if (registr.chnl == BTA_AV_CHNL_AUDIO) { + /* set up the audio stream control block */ + p_scb->p_act_tbl = (const tBTA_AV_ACT *)bta_av_a2d_action; + // p_scb->p_cos = &bta_av_a2d_cos; + p_scb->p_cos = registr.p_bta_av_cos; + p_scb->media_type = AVDT_MEDIA_AUDIO; + cs.cfg.psc_mask = AVDT_PSC_TRANS; + cs.media_type = AVDT_MEDIA_AUDIO; + cs.mtu = p_bta_av_cfg->audio_mtu; + cs.flush_to = L2CAP_DEFAULT_FLUSH_TO; +#if AVDT_REPORTING == TRUE + if (bta_av_cb.features & BTA_AV_FEAT_REPORT) { + cs.cfg.psc_mask |= AVDT_PSC_REPORT; + cs.p_report_cback = bta_av_a2dp_report_cback; +#if AVDT_MULTIPLEXING == TRUE + cs.cfg.mux_tsid_report = 2; +#endif + } +#endif + if (bta_av_cb.features & BTA_AV_FEAT_DELAY_RPT) { + cs.cfg.psc_mask |= AVDT_PSC_DELAY_RPT; + } + + /* keep the configuration in the stream control block */ + memcpy(&p_scb->cfg, &cs.cfg, sizeof(tAVDT_CFG)); + while (index < BTA_AV_MAX_SEPS && + (p_scb->p_cos->init)(&codec_type, cs.cfg.codec_info, + &cs.cfg.num_protect, cs.cfg.protect_info, index) == TRUE) { + +#if (BTA_AV_SINK_INCLUDED == TRUE) + if (index == 1) { + cs.tsep = AVDT_TSEP_SNK; + cs.p_data_cback = bta_av_stream_data_cback; + } + APPL_TRACE_DEBUG(" SEP Type = %d\n", cs.tsep); +#endif + if (AVDT_CreateStream(&p_scb->seps[index].av_handle, &cs) == AVDT_SUCCESS) { + p_scb->seps[index].codec_type = codec_type; + +#if (BTA_AV_SINK_INCLUDED == TRUE) + p_scb->seps[index].tsep = cs.tsep; + if (cs.tsep == AVDT_TSEP_SNK) { + p_scb->seps[index].p_app_data_cback = p_data->api_reg.p_app_data_cback; + } else { + p_scb->seps[index].p_app_data_cback = NULL; /* In case of A2DP SOURCE we don't need a callback to handle media packets */ + } +#endif + + APPL_TRACE_DEBUG("audio[%d] av_handle: %d codec_type: %d\n", + index, p_scb->seps[index].av_handle, p_scb->seps[index].codec_type); + index++; + } else { + break; + } + } + + if (!bta_av_cb.reg_audio) { + /* create the SDP records on the 1st audio channel */ + bta_av_cb.sdp_a2d_handle = SDP_CreateRecord(); + A2D_AddRecord(UUID_SERVCLASS_AUDIO_SOURCE, p_service_name, NULL, + A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_handle); + bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SOURCE); + +#if (BTA_AV_SINK_INCLUDED == TRUE) + bta_av_cb.sdp_a2d_snk_handle = SDP_CreateRecord(); + A2D_AddRecord(UUID_SERVCLASS_AUDIO_SINK, p_avk_service_name, NULL, + A2D_SUPF_PLAYER, bta_av_cb.sdp_a2d_snk_handle); + bta_sys_add_uuid(UUID_SERVCLASS_AUDIO_SINK); +#endif + /* start listening when A2DP is registered */ + if (bta_av_cb.features & BTA_AV_FEAT_RCTG) { + bta_av_rc_create(&bta_av_cb, AVCT_ACP, 0, BTA_AV_NUM_LINKS + 1); + } + + /* if the AV and AVK are both supported, it cannot support the CT role */ + if (bta_av_cb.features & (BTA_AV_FEAT_RCCT)) { + /* if TG is not supported, we need to register to AVCT now */ + if ((bta_av_cb.features & (BTA_AV_FEAT_RCTG)) == 0) { +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) +#if (BTA_AV_WITH_AVCTP_AUTHORIZATION == TRUE) + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + bta_av_cb.sec_mask, BTA_ID_AV); +#else + bta_ar_reg_avct(p_bta_av_cfg->avrc_mtu, p_bta_av_cfg->avrc_br_mtu, + (UINT8)(bta_av_cb.sec_mask & (~BTA_SEC_AUTHORIZE)), BTA_ID_AV); +#endif +#endif + } +#if( defined BTA_AR_INCLUDED ) && (BTA_AR_INCLUDED == TRUE) + /* create an SDP record as AVRC CT. */ + bta_ar_reg_avrc(UUID_SERVCLASS_AV_REMOTE_CONTROL, NULL, NULL, + p_bta_av_cfg->avrc_ct_cat, BTA_ID_AV); +#endif + } + } + bta_av_cb.reg_audio |= BTA_AV_HNDL_TO_MSK(p_scb->hdi); + APPL_TRACE_DEBUG("reg_audio: 0x%x\n", bta_av_cb.reg_audio); + } else { + bta_av_cb.reg_video = BTA_AV_HNDL_TO_MSK(p_scb->hdi); + bta_av_cb.sdp_vdp_handle = SDP_CreateRecord(); + /* register the video channel */ + /* no need to verify the function pointer here. it's verified prior */ + (*p_bta_av_cfg->p_reg)(&cs, p_service_name, p_scb); + } + } while (0); + + /* call callback with register event */ + (*bta_av_cb.p_cback)(BTA_AV_REGISTER_EVT, (tBTA_AV *)®istr); +} + +/******************************************************************************* +** +** Function bta_av_api_deregister +** +** Description de-register a channel +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_api_deregister(tBTA_AV_DATA *p_data) +{ + tBTA_AV_SCB *p_scb = bta_av_hndl_to_scb(p_data->hdr.layer_specific); + + if (p_scb) { + p_scb->deregistring = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_API_CLOSE_EVT, p_data); + } else { + bta_av_dereg_comp(p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_ci_data +** +** Description forward the BTA_AV_CI_SRC_DATA_READY_EVT to stream state machine +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_ci_data(tBTA_AV_DATA *p_data) +{ + tBTA_AV_SCB *p_scb; + int i; + UINT8 chnl = (UINT8)p_data->hdr.layer_specific; + + for ( i = 0; i < BTA_AV_NUM_STRS; i++ ) { + p_scb = bta_av_cb.p_scb[i]; + + if (p_scb && p_scb->chnl == chnl) { + bta_av_ssm_execute(p_scb, BTA_AV_SRC_DATA_READY_EVT, p_data); + } + } +} + +/******************************************************************************* +** +** Function bta_av_rpc_conn +** +** Description report report channel open +** +** Returns void +** +*******************************************************************************/ +#if (AVDT_REPORTING == TRUE) +static void bta_av_rpc_conn(tBTA_AV_DATA *p_data) +{ + UNUSED(p_data); +} +#endif + +/******************************************************************************* +** +** Function bta_av_api_to_ssm +** +** Description forward the API request to stream state machine +** +** +** Returns void +** +*******************************************************************************/ +static void bta_av_api_to_ssm(tBTA_AV_DATA *p_data) +{ + int xx; + UINT16 event = p_data->hdr.event - BTA_AV_FIRST_A2S_API_EVT + BTA_AV_FIRST_A2S_SSM_EVT; + + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + bta_av_ssm_execute(bta_av_cb.p_scb[xx], event, p_data); + } +} + +/******************************************************************************* +** +** Function bta_av_chk_start +** +** Description if this is audio channel, check if more than one audio +** channel is connected & already started. +** +** Returns TRUE, if need api_start +** +*******************************************************************************/ +BOOLEAN bta_av_chk_start(tBTA_AV_SCB *p_scb) +{ + BOOLEAN start = FALSE; + tBTA_AV_SCB *p_scbi; + int i; + + if (p_scb->chnl == BTA_AV_CHNL_AUDIO) { + if ((bta_av_cb.audio_open_cnt >= 2) && + ((0 == (p_scb->role & BTA_AV_ROLE_AD_ACP)) || /* Outgoing connection or */ + (bta_av_cb.features & BTA_AV_FEAT_ACP_START))) { /* auto-starting option */ + /* more than one audio channel is connected */ + /* if this is the 2nd stream as ACP, give INT a chance to issue the START command */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scbi = bta_av_cb.p_scb[i]; + if (p_scbi && p_scbi->chnl == BTA_AV_CHNL_AUDIO && p_scbi->co_started) { + start = TRUE; + /* may need to update the flush timeout of this already started stream */ + if (p_scbi->co_started != bta_av_cb.audio_open_cnt) { + p_scbi->co_started = bta_av_cb.audio_open_cnt; + L2CA_SetFlushTimeout(p_scbi->peer_addr, p_bta_av_cfg->p_audio_flush_to[p_scbi->co_started - 1] ); + } + } + } + } + } + return start; +} + +/******************************************************************************* +** +** Function bta_av_restore_switch +** +** Description assume that the caller of this function already makes +** sure that there's only one ACL connection left +** +** Returns void +** +*******************************************************************************/ +void bta_av_restore_switch (void) +{ + tBTA_AV_CB *p_cb = &bta_av_cb; + int i; + UINT8 mask; + + APPL_TRACE_DEBUG("reg_audio: 0x%x\n", bta_av_cb.reg_audio); + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + mask = BTA_AV_HNDL_TO_MSK(i); + if (p_cb->conn_audio == mask) { + if (p_cb->p_scb[i]) { + bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_cb->p_scb[i]->peer_addr); + } + break; + } + } +} + +/******************************************************************************* +** +** Function bta_av_sys_rs_cback +** +** Description Receives the role change event from dm +** +** Returns (BTA_SYS_ROLE_CHANGE, new_role, hci_status, p_bda) +** +*******************************************************************************/ +static void bta_av_sys_rs_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr) +{ + int i; + tBTA_AV_SCB *p_scb = NULL; + tBTA_AV_ROLE_RES *p_buf; + UINT8 cur_role; + UINT8 peer_idx = 0; + UNUSED(status); + + APPL_TRACE_DEBUG("bta_av_sys_rs_cback: %d\n", bta_av_cb.rs_idx); + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + /* loop through all the SCBs to find matching peer addresses and report the role change event */ + /* note that more than one SCB (a2dp & vdp) maybe waiting for this event */ + p_scb = bta_av_cb.p_scb[i]; + if (p_scb && (bdcmp (peer_addr, p_scb->peer_addr) == 0) && + (p_buf = (tBTA_AV_ROLE_RES *) GKI_getbuf(sizeof(tBTA_AV_ROLE_RES))) != NULL) { + APPL_TRACE_DEBUG("new_role:%d, hci_status:x%x hndl: x%x\n", id, app_id, p_scb->hndl); + /* + if ((id != BTM_ROLE_MASTER) && (app_id != HCI_SUCCESS)) + { + bta_sys_set_policy(BTA_ID_AV, (HCI_ENABLE_MASTER_SLAVE_SWITCH|HCI_ENABLE_SNIFF_MODE), p_scb->peer_addr); + } + */ + p_buf->hdr.event = BTA_AV_ROLE_CHANGE_EVT; + p_buf->hdr.layer_specific = p_scb->hndl; + p_buf->new_role = id; + p_buf->hci_status = app_id; + bta_sys_sendmsg(p_buf); + + peer_idx = p_scb->hdi + 1; /* Handle index for the peer_addr */ + } + } + + /* restore role switch policy, if role switch failed */ + if ((HCI_SUCCESS != app_id) && + (BTM_GetRole (peer_addr, &cur_role) == BTM_SUCCESS) && + (cur_role == BTM_ROLE_SLAVE) ) { + bta_sys_set_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, peer_addr); + } + + /* if BTA_AvOpen() was called for other device, which caused the role switch of the peer_addr, */ + /* we need to continue opening process for the BTA_AvOpen(). */ + if ((bta_av_cb.rs_idx != 0) && (bta_av_cb.rs_idx != peer_idx)) { + if ((bta_av_cb.rs_idx - 1) < BTA_AV_NUM_STRS) { + p_scb = bta_av_cb.p_scb[bta_av_cb.rs_idx - 1]; + } + if (p_scb && p_scb->q_tag == BTA_AV_Q_TAG_OPEN) { + APPL_TRACE_DEBUG ("bta_av_sys_rs_cback: rs_idx(%d), hndl:x%x q_tag: %d\n", + bta_av_cb.rs_idx, p_scb->hndl, p_scb->q_tag); + + if (HCI_SUCCESS == app_id || HCI_ERR_NO_CONNECTION == app_id) { + p_scb->q_info.open.switch_res = BTA_AV_RS_OK; + } else { + p_scb->q_info.open.switch_res = BTA_AV_RS_FAIL; + } + + /* Continue av open process */ + bta_av_do_disc_a2d (p_scb, (tBTA_AV_DATA *) & (p_scb->q_info.open)); + } + + bta_av_cb.rs_idx = 0; + } +} + +/******************************************************************************* +** +** Function bta_av_sco_chg_cback +** +** Description receive & process the SCO connection up/down event from sys. +** call setup also triggers this callback, to suspend av before sco +** activity happens, or to resume av once call ends. +** +** Returns void +** +*******************************************************************************/ +static void bta_av_sco_chg_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 + app_id, BD_ADDR peer_addr) +{ + tBTA_AV_SCB *p_scb; + int i; + tBTA_AV_API_STOP stop; + UNUSED(app_id); + UNUSED(peer_addr); + + APPL_TRACE_DEBUG("bta_av_sco_chg_cback:%d status:%d\n", id, status); + if (id) { + bta_av_cb.sco_occupied = TRUE; + + /* either BTA_SYS_SCO_OPEN or BTA_SYS_SCO_CLOSE with remaining active SCO */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scb = bta_av_cb.p_scb[i]; + + if ( p_scb && p_scb->co_started && (p_scb->sco_suspend == FALSE)) { + APPL_TRACE_DEBUG("suspending scb:%d\n", i); + /* scb is used and started, not suspended automatically */ + p_scb->sco_suspend = TRUE; + stop.flush = FALSE; + stop.suspend = TRUE; + bta_av_ssm_execute(p_scb, BTA_AV_AP_STOP_EVT, (tBTA_AV_DATA *)&stop); + } + } + } else { + bta_av_cb.sco_occupied = FALSE; + + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scb = bta_av_cb.p_scb[i]; + + if ( p_scb && p_scb->sco_suspend ) { /* scb is used and suspended for SCO */ + APPL_TRACE_DEBUG("starting scb:%d\n", i); + bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL); + } + } + } +} + +/******************************************************************************* +** +** Function bta_av_switch_if_needed +** +** Description This function checks if there is another existing AV +** channel that is local as slave role. +** If so, role switch and remove it from link policy. +** +** Returns TRUE, if role switch is done +** +*******************************************************************************/ +BOOLEAN bta_av_switch_if_needed(tBTA_AV_SCB *p_scb) +{ + UINT8 role; + BOOLEAN needed = FALSE; + tBTA_AV_SCB *p_scbi; + int i; + UINT8 mask; + + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + mask = BTA_AV_HNDL_TO_MSK(i); + p_scbi = bta_av_cb.p_scb[i]; + if ( p_scbi && (p_scb->hdi != i) && /* not the original channel */ + ((bta_av_cb.conn_audio & mask) ||/* connected audio */ + (bta_av_cb.conn_video & mask)) ) { /* connected video */ + BTM_GetRole(p_scbi->peer_addr, &role); + /* this channel is open - clear the role switch link policy for this link */ + if (BTM_ROLE_MASTER != role) { + if (bta_av_cb.features & BTA_AV_FEAT_MASTER) { + bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scbi->peer_addr); + } + if (BTM_CMD_STARTED != BTM_SwitchRole(p_scbi->peer_addr, BTM_ROLE_MASTER, NULL)) { + /* can not switch role on SCBI + * start the timer on SCB - because this function is ONLY called when SCB gets API_OPEN */ + bta_sys_start_timer(&p_scb->timer, BTA_AV_AVRC_TIMER_EVT, BTA_AV_RS_TIME_VAL); + } + needed = TRUE; + /* mark the original channel as waiting for RS result */ + bta_av_cb.rs_idx = p_scb->hdi + 1; + break; + } + } + } + return needed; +} + +/******************************************************************************* +** +** Function bta_av_link_role_ok +** +** Description This function checks if the SCB has existing ACL connection +** If so, check if the link role fits the requirements. +** +** Returns TRUE, if role is ok +** +*******************************************************************************/ +BOOLEAN bta_av_link_role_ok(tBTA_AV_SCB *p_scb, UINT8 bits) +{ + UINT8 role; + BOOLEAN is_ok = TRUE; + + if (BTM_GetRole(p_scb->peer_addr, &role) == BTM_SUCCESS) { + LOG_INFO("%s hndl:x%x role:%d conn_audio:x%x bits:%d features:x%x\n", + __func__, p_scb->hndl, role, bta_av_cb.conn_audio, bits, + bta_av_cb.features); + if (BTM_ROLE_MASTER != role && (A2D_BitsSet(bta_av_cb.conn_audio) > bits || (bta_av_cb.features & BTA_AV_FEAT_MASTER))) { + if (bta_av_cb.features & BTA_AV_FEAT_MASTER) { + bta_sys_clear_policy(BTA_ID_AV, HCI_ENABLE_MASTER_SLAVE_SWITCH, p_scb->peer_addr); + } + + if (BTM_CMD_STARTED != BTM_SwitchRole(p_scb->peer_addr, BTM_ROLE_MASTER, NULL)) { + /* can not switch role on SCB - start the timer on SCB */ + } + is_ok = FALSE; + p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START; + + } + } + + return is_ok; +} + +/******************************************************************************* +** +** Function bta_av_chk_mtu +** +** Description if this is audio channel, check if more than one audio +** channel is connected. +** +** Returns The smallest mtu of the connected audio channels +** +*******************************************************************************/ +UINT16 bta_av_chk_mtu(tBTA_AV_SCB *p_scb, UINT16 mtu) +{ + UINT16 ret_mtu = BTA_AV_MAX_A2DP_MTU; + tBTA_AV_SCB *p_scbi; + int i; + UINT8 mask; + UNUSED(mtu); + + /* TODO_MV mess with the mtu according to the number of EDR/non-EDR headsets */ + if (p_scb->chnl == BTA_AV_CHNL_AUDIO) { + if (bta_av_cb.audio_open_cnt >= 2) { + /* more than one audio channel is connected */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scbi = bta_av_cb.p_scb[i]; + if ((p_scb != p_scbi) && p_scbi && (p_scbi->chnl == BTA_AV_CHNL_AUDIO) ) { + mask = BTA_AV_HNDL_TO_MSK(i); + APPL_TRACE_DEBUG("[%d] mtu: %d, mask:0x%x\n", + i, p_scbi->stream_mtu, mask); + if (bta_av_cb.conn_audio & mask) { + if (ret_mtu > p_scbi->stream_mtu) { + ret_mtu = p_scbi->stream_mtu; + } + } + } + } + } + APPL_TRACE_DEBUG("bta_av_chk_mtu audio count:%d, conn_audio:0x%x, ret:%d\n", + bta_av_cb.audio_open_cnt, bta_av_cb.conn_audio, ret_mtu); + } + return ret_mtu; +} + +/******************************************************************************* +** +** Function bta_av_dup_audio_buf +** +** Description dup the audio data to the q_info.a2d of other audio channels +** +** Returns void +** +*******************************************************************************/ +void bta_av_dup_audio_buf(tBTA_AV_SCB *p_scb, BT_HDR *p_buf) +{ + tBTA_AV_SCB *p_scbi; + int i; + UINT16 size, copy_size; + BT_HDR *p_new; + + if (!p_buf) { + return; + } + + if (bta_av_cb.audio_open_cnt >= 2) { + size = GKI_get_buf_size(p_buf); + copy_size = BT_HDR_SIZE + p_buf->len + p_buf->offset; + /* more than one audio channel is connected */ + for (i = 0; i < BTA_AV_NUM_STRS; i++) { + p_scbi = bta_av_cb.p_scb[i]; + if ( (p_scb->hdi != i) && /* not the original channel */ + (bta_av_cb.conn_audio & BTA_AV_HNDL_TO_MSK(i)) && /* connected audio */ + p_scbi && p_scbi->co_started ) { /* scb is used and started */ + /* enqueue the data only when the stream is started */ + p_new = (BT_HDR *)GKI_getbuf(size); + if (p_new) { + memcpy(p_new, p_buf, copy_size); + list_append(p_scbi->a2d_list, p_new); + if (list_length(p_scbi->a2d_list) > p_bta_av_cfg->audio_mqs) { + // Drop the oldest packet + bta_av_co_audio_drop(p_scbi->hndl); + BT_HDR *p_buf = list_front(p_scbi->a2d_list); + list_remove(p_scbi->a2d_list, p_buf); + GKI_freebuf(p_buf); + } + } + } + } + } + +} + +/******************************************************************************* +** +** Function bta_av_sm_execute +** +** Description State machine event handling function for AV +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_sm_execute(tBTA_AV_CB *p_cb, UINT16 event, tBTA_AV_DATA *p_data) +{ + tBTA_AV_ST_TBL state_table; + UINT8 action; + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_EVENT("AV event=0x%x(%s) state=%d(%s)\n", + event, bta_av_evt_code(event), p_cb->state, bta_av_st_code(p_cb->state)); +#else + APPL_TRACE_EVENT("AV event=0x%x state=%d\n", event, p_cb->state); +#endif + + /* look up the state table for the current state */ + state_table = bta_av_st_tbl[p_cb->state]; + + event &= 0x00FF; + + /* set next state */ + p_cb->state = state_table[event][BTA_AV_NEXT_STATE]; + APPL_TRACE_EVENT("next state=%d\n", p_cb->state); + + /* execute action functions */ + if ((action = state_table[event][BTA_AV_ACTION_COL]) != BTA_AV_IGNORE) { + (*bta_av_action[action])(p_cb, p_data); + } +} + + +/******************************************************************************* +** +** Function bta_av_hdl_event +** +** Description Advanced audio/video main event handling function. +** +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN bta_av_hdl_event(BT_HDR *p_msg) +{ + UINT16 event = p_msg->event; + UINT16 first_event = BTA_AV_FIRST_NSM_EVT; + + if (event > BTA_AV_LAST_EVT) { + return TRUE; /* to free p_msg */ + } + + if (event >= first_event) { +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_VERBOSE("AV nsm event=0x%x(%s)\n", event, bta_av_evt_code(event)); +#else + APPL_TRACE_VERBOSE("AV nsm event=0x%x\n", event); +#endif + /* non state machine events */ + (*bta_av_nsm_act[event - BTA_AV_FIRST_NSM_EVT]) ((tBTA_AV_DATA *) p_msg); + } else if (event >= BTA_AV_FIRST_SM_EVT && event <= BTA_AV_LAST_SM_EVT) { +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_VERBOSE("AV sm event=0x%x(%s)\n", event, bta_av_evt_code(event)); +#else + APPL_TRACE_VERBOSE("AV sm event=0x%x\n", event); +#endif + /* state machine events */ + bta_av_sm_execute(&bta_av_cb, p_msg->event, (tBTA_AV_DATA *) p_msg); + } else { + APPL_TRACE_VERBOSE("handle=0x%x\n", p_msg->layer_specific); + /* stream state machine events */ + bta_av_ssm_execute( bta_av_hndl_to_scb(p_msg->layer_specific), + p_msg->event, (tBTA_AV_DATA *) p_msg); + } + return TRUE; +} + + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +/******************************************************************************* +** +** Function bta_av_st_code +** +** Description +** +** Returns char * +** +*******************************************************************************/ +static char *bta_av_st_code(UINT8 state) +{ + switch (state) { + case BTA_AV_INIT_ST: return "INIT"; + case BTA_AV_OPEN_ST: return "OPEN"; + default: return "unknown"; + } +} +/******************************************************************************* +** +** Function bta_av_evt_code +** +** Description +** +** Returns char * +** +*******************************************************************************/ +char *bta_av_evt_code(UINT16 evt_code) +{ + switch (evt_code) { + case BTA_AV_API_DISABLE_EVT: return "API_DISABLE"; + case BTA_AV_API_REMOTE_CMD_EVT: return "API_REMOTE_CMD"; + case BTA_AV_API_VENDOR_CMD_EVT: return "API_VENDOR_CMD"; + case BTA_AV_API_VENDOR_RSP_EVT: return "API_VENDOR_RSP"; + case BTA_AV_API_META_RSP_EVT: return "API_META_RSP_EVT"; + case BTA_AV_API_RC_CLOSE_EVT: return "API_RC_CLOSE"; + case BTA_AV_AVRC_OPEN_EVT: return "AVRC_OPEN"; + case BTA_AV_AVRC_MSG_EVT: return "AVRC_MSG"; + case BTA_AV_AVRC_NONE_EVT: return "AVRC_NONE"; + + case BTA_AV_API_OPEN_EVT: return "API_OPEN"; + case BTA_AV_API_CLOSE_EVT: return "API_CLOSE"; + case BTA_AV_AP_START_EVT: return "AP_START"; + case BTA_AV_AP_STOP_EVT: return "AP_STOP"; + case BTA_AV_API_RECONFIG_EVT: return "API_RECONFIG"; + case BTA_AV_API_PROTECT_REQ_EVT: return "API_PROTECT_REQ"; + case BTA_AV_API_PROTECT_RSP_EVT: return "API_PROTECT_RSP"; + case BTA_AV_API_RC_OPEN_EVT: return "API_RC_OPEN"; + case BTA_AV_SRC_DATA_READY_EVT: return "SRC_DATA_READY"; + case BTA_AV_CI_SETCONFIG_OK_EVT: return "CI_SETCONFIG_OK"; + case BTA_AV_CI_SETCONFIG_FAIL_EVT: return "CI_SETCONFIG_FAIL"; + case BTA_AV_SDP_DISC_OK_EVT: return "SDP_DISC_OK"; + case BTA_AV_SDP_DISC_FAIL_EVT: return "SDP_DISC_FAIL"; + case BTA_AV_STR_DISC_OK_EVT: return "STR_DISC_OK"; + case BTA_AV_STR_DISC_FAIL_EVT: return "STR_DISC_FAIL"; + case BTA_AV_STR_GETCAP_OK_EVT: return "STR_GETCAP_OK"; + case BTA_AV_STR_GETCAP_FAIL_EVT: return "STR_GETCAP_FAIL"; + case BTA_AV_STR_OPEN_OK_EVT: return "STR_OPEN_OK"; + case BTA_AV_STR_OPEN_FAIL_EVT: return "STR_OPEN_FAIL"; + case BTA_AV_STR_START_OK_EVT: return "STR_START_OK"; + case BTA_AV_STR_START_FAIL_EVT: return "STR_START_FAIL"; + case BTA_AV_STR_CLOSE_EVT: return "STR_CLOSE"; + case BTA_AV_STR_CONFIG_IND_EVT: return "STR_CONFIG_IND"; + case BTA_AV_STR_SECURITY_IND_EVT: return "STR_SECURITY_IND"; + case BTA_AV_STR_SECURITY_CFM_EVT: return "STR_SECURITY_CFM"; + case BTA_AV_STR_WRITE_CFM_EVT: return "STR_WRITE_CFM"; + case BTA_AV_STR_SUSPEND_CFM_EVT: return "STR_SUSPEND_CFM"; + case BTA_AV_STR_RECONFIG_CFM_EVT: return "STR_RECONFIG_CFM"; + case BTA_AV_AVRC_TIMER_EVT: return "AVRC_TIMER"; + case BTA_AV_AVDT_CONNECT_EVT: return "AVDT_CONNECT"; + case BTA_AV_AVDT_DISCONNECT_EVT: return "AVDT_DISCONNECT"; + case BTA_AV_ROLE_CHANGE_EVT: return "ROLE_CHANGE"; + case BTA_AV_AVDT_DELAY_RPT_EVT: return "AVDT_DELAY_RPT"; + case BTA_AV_ACP_CONNECT_EVT: return "ACP_CONNECT"; + + case BTA_AV_API_ENABLE_EVT: return "API_ENABLE"; + case BTA_AV_API_REGISTER_EVT: return "API_REG"; + case BTA_AV_API_DEREGISTER_EVT: return "API_DEREG"; + case BTA_AV_API_DISCONNECT_EVT: return "API_DISCNT"; + case BTA_AV_CI_SRC_DATA_READY_EVT: return "CI_DATA_READY"; + case BTA_AV_SIG_CHG_EVT: return "SIG_CHG"; + case BTA_AV_SIG_TIMER_EVT: return "SIG_TMR"; + case BTA_AV_SDP_AVRC_DISC_EVT: return "SDP_AVRC_DISC"; + case BTA_AV_AVRC_CLOSE_EVT: return "AVRC_CLOSE"; + case BTA_AV_CONN_CHG_EVT: return "CONN_CHG"; + case BTA_AV_DEREG_COMP_EVT: return "DEREG_COMP"; +#if (BTA_AV_SINK_INCLUDED == TRUE) + case BTA_AV_API_SINK_ENABLE_EVT: return "SINK_ENABLE"; +#endif +#if (AVDT_REPORTING == TRUE) + case BTA_AV_AVDT_RPT_CONN_EVT: return "RPT_CONN"; +#endif + case BTA_AV_API_START_EVT: return "API_START"; + case BTA_AV_API_STOP_EVT: return "API_STOP"; + default: return "unknown"; + } +} +#endif + +#endif /* BTA_AV_INCLUDED */ diff --git a/components/bt/bluedroid/bta/av/bta_av_sbc.c b/components/bt/bluedroid/bta/av/bta_av_sbc.c new file mode 100644 index 0000000000..812876ff23 --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_sbc.c @@ -0,0 +1,614 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains utility functions for dealing with SBC data frames + * and codec capabilities. + * + ******************************************************************************/ + +#include "bt_target.h" +#include "a2d_api.h" +#include "a2d_sbc.h" +#include "bta_av_sbc.h" +#include "utl.h" +#include "bt_utils.h" + +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +typedef int (tBTA_AV_SBC_ACT)(void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +typedef struct { + INT32 cur_pos; /* current position */ + UINT32 src_sps; /* samples per second (source audio data) */ + UINT32 dst_sps; /* samples per second (converted audio data) */ + tBTA_AV_SBC_ACT *p_act; /* the action function to do the conversion */ + UINT16 bits; /* number of bits per pcm sample */ + UINT16 n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */ + INT16 worker1; + INT16 worker2; + UINT8 div; +} tBTA_AV_SBC_UPS_CB; + +tBTA_AV_SBC_UPS_CB bta_av_sbc_ups_cb; + +/******************************************************************************* +** +** Function bta_av_sbc_init_up_sample +** +** Description initialize the up sample +** +** src_sps: samples per second (source audio data) +** dst_sps: samples per second (converted audio data) +** bits: number of bits per pcm sample +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +void bta_av_sbc_init_up_sample (UINT32 src_sps, UINT32 dst_sps, UINT16 bits, UINT16 n_channels) +{ + bta_av_sbc_ups_cb.cur_pos = -1; + bta_av_sbc_ups_cb.src_sps = src_sps; + bta_av_sbc_ups_cb.dst_sps = dst_sps; + bta_av_sbc_ups_cb.bits = bits; + bta_av_sbc_ups_cb.n_channels = n_channels; + + if (n_channels == 1) { + /* mono */ + if (bits == 8) { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_8m; + bta_av_sbc_ups_cb.div = 1; + } else { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_16m; + bta_av_sbc_ups_cb.div = 2; + } + } else { + /* stereo */ + if (bits == 8) { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_8s; + bta_av_sbc_ups_cb.div = 2; + } else { + bta_av_sbc_ups_cb.p_act = bta_av_sbc_up_sample_16s; + bta_av_sbc_ups_cb.div = 4; + } + } +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Note: An AE reported an issue with this function. +** When called with bta_av_sbc_up_sample(src, uint8_array_dst..) +** the byte before uint8_array_dst may get overwritten. +** Using uint16_array_dst avoids the problem. +** This issue is related to endian-ness and is hard to resolve +** in a generic manner. +** **************** Please use uint16 array as dst. +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + UINT32 src; + UINT32 dst; + + if (bta_av_sbc_ups_cb.p_act) { + src = src_samples / bta_av_sbc_ups_cb.div; + dst = dst_samples / bta_av_sbc_ups_cb.div; + return (*bta_av_sbc_ups_cb.p_act)(p_src, p_dst, src, dst, p_ret); + } else { + *p_ret = 0; + return 0; + } +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16s (16bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 4 bytes) +** dst_samples: The size of p_dst (in uint of 4 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + INT16 *p_src_tmp = (INT16 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker1 = &bta_av_sbc_ups_cb.worker1; + INT16 *p_worker2 = &bta_av_sbc_ups_cb.worker2; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + } + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples-- && dst_samples) { + *p_worker1 = *p_src_tmp++; + *p_worker2 = *p_src_tmp++; + + do { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) { + bta_av_sbc_ups_cb.cur_pos = 0; + } + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16m (16bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + INT16 *p_src_tmp = (INT16 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker = &bta_av_sbc_ups_cb.worker1; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + } + + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples-- && dst_samples) { + *p_worker = *p_src_tmp++; + + do { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) { + bta_av_sbc_ups_cb.cur_pos = 0; + } + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8s (8bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + UINT8 *p_src_tmp = (UINT8 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker1 = &bta_av_sbc_ups_cb.worker1; + INT16 *p_worker2 = &bta_av_sbc_ups_cb.worker2; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + } + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples -- && dst_samples) { + *p_worker1 = *(UINT8 *)p_src_tmp++; + *p_worker1 -= 0x80; + *p_worker1 <<= 8; + *p_worker2 = *(UINT8 *)p_src_tmp++; + *p_worker2 -= 0x80; + *p_worker2 <<= 8; + + do { + *p_dst_tmp++ = *p_worker1; + *p_dst_tmp++ = *p_worker2; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples--; + dst_samples--; + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) { + bta_av_sbc_ups_cb.cur_pos = 0; + } + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8m (8bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +int bta_av_sbc_up_sample_8m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret) +{ + UINT8 *p_src_tmp = (UINT8 *)p_src; + INT16 *p_dst_tmp = (INT16 *)p_dst; + INT16 *p_worker = &bta_av_sbc_ups_cb.worker1; + UINT32 src_sps = bta_av_sbc_ups_cb.src_sps; + UINT32 dst_sps = bta_av_sbc_ups_cb.dst_sps; + + while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples) { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples -= 4; + } + + + bta_av_sbc_ups_cb.cur_pos = dst_sps; + + while (src_samples-- && dst_samples) { + *p_worker = *(UINT8 *)p_src_tmp++; + *p_worker -= 0x80; + *p_worker <<= 8; + + do { + *p_dst_tmp++ = *p_worker; + *p_dst_tmp++ = *p_worker; + + bta_av_sbc_ups_cb.cur_pos -= src_sps; + dst_samples -= 4; + + } while (bta_av_sbc_ups_cb.cur_pos > 0 && dst_samples); + + bta_av_sbc_ups_cb.cur_pos += dst_sps; + } + + if (bta_av_sbc_ups_cb.cur_pos == (INT32)dst_sps) { + bta_av_sbc_ups_cb.cur_pos = 0; + } + + *p_ret = ((char *)p_src_tmp - (char *)p_src); + return ((char *)p_dst_tmp - (char *)p_dst); +} + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_for_cap +** +** Description Determine the preferred SBC codec configuration for the +** given codec capabilities. The function is passed the +** preferred codec configuration and the peer codec +** capabilities for the stream. The function attempts to +** match the preferred capabilities with the configuration +** as best it can. The resulting codec configuration is +** returned in the same memory used for the capabilities. +** +** Returns 0 if ok, nonzero if error. +** Codec configuration in p_cap. +** +*******************************************************************************/ +UINT8 bta_av_sbc_cfg_for_cap(UINT8 *p_peer, tA2D_SBC_CIE *p_cap, tA2D_SBC_CIE *p_pref) +{ + UINT8 status = A2D_SUCCESS; + tA2D_SBC_CIE peer_cie; + UNUSED(p_cap); + + /* parse peer capabilities */ + if ((status = A2D_ParsSbcInfo(&peer_cie, p_peer, TRUE)) != 0) { + return status; + } + + /* Check if the peer supports our channel mode */ + if (peer_cie.ch_mode & p_pref->ch_mode) { + peer_cie.ch_mode = p_pref->ch_mode; + } else { + APPL_TRACE_ERROR("bta_av_sbc_cfg_for_cap: ch_mode(0x%02X) not supported", p_pref->ch_mode); + return A2D_FAIL; + } + + /* Check if the peer supports our sampling freq */ + if (peer_cie.samp_freq & p_pref->samp_freq) { + peer_cie.samp_freq = p_pref->samp_freq; + } else { + APPL_TRACE_ERROR("bta_av_sbc_cfg_for_cap: samp_freq(0x%02X) not supported", p_pref->samp_freq); + return A2D_FAIL; + } + + /* Check if the peer supports our block len */ + if (peer_cie.block_len & p_pref->block_len) { + peer_cie.block_len = p_pref->block_len; + } else { + APPL_TRACE_ERROR("bta_av_sbc_cfg_for_cap: block_len(0x%02X) not supported", p_pref->block_len); + return A2D_FAIL; + } + + /* Check if the peer supports our num subbands */ + if (peer_cie.num_subbands & p_pref->num_subbands) { + peer_cie.num_subbands = p_pref->num_subbands; + } else { + APPL_TRACE_ERROR("bta_av_sbc_cfg_for_cap: num_subbands(0x%02X) not supported", p_pref->num_subbands); + return A2D_FAIL; + } + + /* Check if the peer supports our alloc method */ + if (peer_cie.alloc_mthd & p_pref->alloc_mthd) { + peer_cie.alloc_mthd = p_pref->alloc_mthd; + } else { + APPL_TRACE_ERROR("bta_av_sbc_cfg_for_cap: alloc_mthd(0x%02X) not supported", p_pref->alloc_mthd); + return A2D_FAIL; + } + + /* max bitpool */ + if (p_pref->max_bitpool != 0 && p_pref->max_bitpool < peer_cie.max_bitpool) { + peer_cie.max_bitpool = p_pref->max_bitpool; + } + + /* min bitpool */ + if (p_pref->min_bitpool != 0 && p_pref->min_bitpool > peer_cie.min_bitpool) { + peer_cie.min_bitpool = p_pref->min_bitpool; + } + + if (status == A2D_SUCCESS) { + /* build configuration */ + A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &peer_cie, p_peer); + } + return status; +} + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_matches_cap +** +** Description This function checks whether an SBC codec configuration +** matched with capabilities. Here we check subset. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +UINT8 bta_av_sbc_cfg_matches_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap) +{ + UINT8 status = 0; + tA2D_SBC_CIE cfg_cie; + + /* parse configuration */ + if ((status = A2D_ParsSbcInfo(&cfg_cie, p_cfg, TRUE)) != 0) { + APPL_TRACE_ERROR(" bta_av_sbc_cfg_matches_cap Parsing Failed %d", status); + return status; + } + + /* verify that each parameter is in range */ + + APPL_TRACE_DEBUG(" FREQ peer: 0%x, capability 0%x", cfg_cie.samp_freq, p_cap->samp_freq); + APPL_TRACE_DEBUG(" CH_MODE peer: 0%x, capability 0%x", cfg_cie.ch_mode, p_cap->ch_mode); + APPL_TRACE_DEBUG(" BLOCK_LEN peer: 0%x, capability 0%x", cfg_cie.block_len, p_cap->block_len); + APPL_TRACE_DEBUG(" SUB_BAND peer: 0%x, capability 0%x", cfg_cie.num_subbands, p_cap->num_subbands); + APPL_TRACE_DEBUG(" ALLOC_MTHD peer: 0%x, capability 0%x", cfg_cie.alloc_mthd, p_cap->alloc_mthd); + APPL_TRACE_DEBUG(" MAX_BitPool peer: 0%x, capability 0%x", cfg_cie.max_bitpool, p_cap->max_bitpool); + APPL_TRACE_DEBUG(" Min_bitpool peer: 0%x, capability 0%x", cfg_cie.min_bitpool, p_cap->min_bitpool); + + /* sampling frequency */ + if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0) { + status = A2D_NS_SAMP_FREQ; + } + /* channel mode */ + else if ((cfg_cie.ch_mode & p_cap->ch_mode) == 0) { + status = A2D_NS_CH_MODE; + } + /* block length */ + else if ((cfg_cie.block_len & p_cap->block_len) == 0) { + status = A2D_BAD_BLOCK_LEN; + } + /* subbands */ + else if ((cfg_cie.num_subbands & p_cap->num_subbands) == 0) { + status = A2D_NS_SUBBANDS; + } + /* allocation method */ + else if ((cfg_cie.alloc_mthd & p_cap->alloc_mthd) == 0) { + status = A2D_NS_ALLOC_MTHD; + } + /* max bitpool */ + else if (cfg_cie.max_bitpool > p_cap->max_bitpool) { + status = A2D_NS_MAX_BITPOOL; + } + /* min bitpool */ + else if (cfg_cie.min_bitpool < p_cap->min_bitpool) { + status = A2D_NS_MIN_BITPOOL; + } + + return status; +} + + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_in_cap +** +** Description This function checks whether an SBC codec configuration +** is allowable for the given codec capabilities. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap) +{ + UINT8 status = 0; + tA2D_SBC_CIE cfg_cie; + + /* parse configuration */ + if ((status = A2D_ParsSbcInfo(&cfg_cie, p_cfg, FALSE)) != 0) { + return status; + } + + /* verify that each parameter is in range */ + + + /* sampling frequency */ + if ((cfg_cie.samp_freq & p_cap->samp_freq) == 0) { + status = A2D_NS_SAMP_FREQ; + } + /* channel mode */ + else if ((cfg_cie.ch_mode & p_cap->ch_mode) == 0) { + status = A2D_NS_CH_MODE; + } + /* block length */ + else if ((cfg_cie.block_len & p_cap->block_len) == 0) { + status = A2D_BAD_BLOCK_LEN; + } + /* subbands */ + else if ((cfg_cie.num_subbands & p_cap->num_subbands) == 0) { + status = A2D_NS_SUBBANDS; + } + /* allocation method */ + else if ((cfg_cie.alloc_mthd & p_cap->alloc_mthd) == 0) { + status = A2D_NS_ALLOC_MTHD; + } + /* max bitpool */ + else if (cfg_cie.max_bitpool > p_cap->max_bitpool) { + status = A2D_NS_MAX_BITPOOL; + } + /* min bitpool */ + else if (cfg_cie.min_bitpool < p_cap->min_bitpool) { + status = A2D_NS_MIN_BITPOOL; + } + + return status; +} + +/******************************************************************************* +** +** Function bta_av_sbc_bld_hdr +** +** Description This function builds the packet header for MPF1. +** +** Returns void +** +*******************************************************************************/ +void bta_av_sbc_bld_hdr(BT_HDR *p_buf, UINT16 fr_per_pkt) +{ + UINT8 *p; + + p_buf->offset -= BTA_AV_SBC_HDR_SIZE; + p = (UINT8 *) (p_buf + 1) + p_buf->offset; + p_buf->len += BTA_AV_SBC_HDR_SIZE; + A2D_BldSbcMplHdr(p, FALSE, FALSE, FALSE, (UINT8) fr_per_pkt); +} + +#endif /* #if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/av/bta_av_ssm.c b/components/bt/bluedroid/bta/av/bta_av_ssm.c new file mode 100644 index 0000000000..c08d77c999 --- /dev/null +++ b/components/bt/bluedroid/bta/av/bta_av_ssm.c @@ -0,0 +1,580 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the stream state machine for the BTA advanced audio/video. + * + ******************************************************************************/ + +#include "bt_target.h" +#if defined(BTA_AV_INCLUDED) && (BTA_AV_INCLUDED == TRUE) + +#include +#include "bta_av_co.h" +#include "bta_av_int.h" + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +/* state machine states */ +enum { + BTA_AV_INIT_SST, + BTA_AV_INCOMING_SST, + BTA_AV_OPENING_SST, + BTA_AV_OPEN_SST, + BTA_AV_RCFG_SST, + BTA_AV_CLOSING_SST +}; + + +/* state machine action enumeration list */ +enum { + BTA_AV_DO_DISC, + BTA_AV_CLEANUP, + BTA_AV_FREE_SDB, + BTA_AV_CONFIG_IND, + BTA_AV_DISCONNECT_REQ, + BTA_AV_SECURITY_REQ, + BTA_AV_SECURITY_RSP, + BTA_AV_SETCONFIG_RSP, + BTA_AV_ST_RC_TIMER, + BTA_AV_STR_OPENED, + BTA_AV_SECURITY_IND, + BTA_AV_SECURITY_CFM, + BTA_AV_DO_CLOSE, + BTA_AV_CONNECT_REQ, + BTA_AV_SDP_FAILED, + BTA_AV_DISC_RESULTS, + BTA_AV_DISC_RES_AS_ACP, + BTA_AV_OPEN_FAILED, + BTA_AV_GETCAP_RESULTS, + BTA_AV_SETCONFIG_REJ, + BTA_AV_DISCOVER_REQ, + BTA_AV_CONN_FAILED, + BTA_AV_DO_START, + BTA_AV_STR_STOPPED, + BTA_AV_RECONFIG, + BTA_AV_DATA_PATH, + BTA_AV_START_OK, + BTA_AV_START_FAILED, + BTA_AV_STR_CLOSED, + BTA_AV_CLR_CONG, + BTA_AV_SUSPEND_CFM, + BTA_AV_RCFG_STR_OK, + BTA_AV_RCFG_FAILED, + BTA_AV_RCFG_CONNECT, + BTA_AV_RCFG_DISCNTD, + BTA_AV_SUSPEND_CONT, + BTA_AV_RCFG_CFM, + BTA_AV_RCFG_OPEN, + BTA_AV_SECURITY_REJ, + BTA_AV_OPEN_RC, + BTA_AV_CHK_2ND_START, + BTA_AV_SAVE_CAPS, + BTA_AV_SET_USE_RC, + BTA_AV_CCO_CLOSE, + BTA_AV_SWITCH_ROLE, + BTA_AV_ROLE_RES, + BTA_AV_DELAY_CO, + BTA_AV_OPEN_AT_INC, + BTA_AV_NUM_SACTIONS +}; + +#define BTA_AV_SIGNORE BTA_AV_NUM_SACTIONS + + +/* state table information */ +/* #define BTA_AV_SACTION_COL 0 position of actions */ +#define BTA_AV_SACTIONS 2 /* number of actions */ +#define BTA_AV_SNEXT_STATE 2 /* position of next state */ +#define BTA_AV_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for init state */ +static const UINT8 bta_av_sst_init[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* AP_OPEN_EVT */ {BTA_AV_DO_DISC, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* AP_CLOSE_EVT */ {BTA_AV_CLEANUP, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* AVDT_DISCONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST } +}; + +/* state table for incoming state */ +static const UINT8 bta_av_sst_incoming[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* AP_OPEN_EVT */ {BTA_AV_OPEN_AT_INC, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* AP_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_DISCONNECT_REQ, BTA_AV_CLOSING_SST }, + /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SETCONFIG_RSP, BTA_AV_ST_RC_TIMER, BTA_AV_INCOMING_SST }, + /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, + /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RES_AS_ACP, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_OPEN_OK_EVT */ {BTA_AV_STR_OPENED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_CLOSE_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, + /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* AVDT_DISCONNECT_EVT */ {BTA_AV_CCO_CLOSE, BTA_AV_CLEANUP, BTA_AV_INIT_SST }, + /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST } +}; + +/* state table for opening state */ +static const UINT8 bta_av_sst_opening[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* SDP_DISC_OK_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* SDP_DISC_FAIL_EVT */ {BTA_AV_CONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_DISC_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_GETCAP_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_OPEN_OK_EVT */ {BTA_AV_ST_RC_TIMER, BTA_AV_STR_OPENED, BTA_AV_OPEN_SST }, + /* STR_OPEN_FAIL_EVT */ {BTA_AV_OPEN_FAILED, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_CLOSE_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_CONFIG_IND_EVT */ {BTA_AV_CONFIG_IND, BTA_AV_SIGNORE, BTA_AV_INCOMING_SST }, + /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* AVRC_TIMER_EVT */ {BTA_AV_SWITCH_ROLE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* AVDT_CONNECT_EVT */ {BTA_AV_DISCOVER_REQ, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* AVDT_DISCONNECT_EVT */ {BTA_AV_CONN_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPENING_SST }, + /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPENING_SST } +}; + +/* state table for open state */ +static const UINT8 bta_av_sst_open[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* AP_CLOSE_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AP_START_EVT */ {BTA_AV_DO_START, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* AP_STOP_EVT */ {BTA_AV_STR_STOPPED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* API_RECONFIG_EVT */ {BTA_AV_RECONFIG, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* API_PROTECT_REQ_EVT */ {BTA_AV_SECURITY_REQ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* API_PROTECT_RSP_EVT */ {BTA_AV_SECURITY_RSP, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* API_RC_OPEN_EVT */ {BTA_AV_SET_USE_RC, BTA_AV_OPEN_RC, BTA_AV_OPEN_SST }, + /* SRC_DATA_READY_EVT */ {BTA_AV_DATA_PATH, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_GETCAP_OK_EVT */ {BTA_AV_SAVE_CAPS, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_OPEN_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_OPEN_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_START_OK_EVT */ {BTA_AV_START_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_START_FAIL_EVT */ {BTA_AV_START_FAILED, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_CLOSE_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_IND, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_SECURITY_CFM_EVT */ {BTA_AV_SECURITY_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_WRITE_CFM_EVT */ {BTA_AV_CLR_CONG, BTA_AV_DATA_PATH, BTA_AV_OPEN_SST }, + /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CFM, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* AVRC_TIMER_EVT */ {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST }, + /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* ROLE_CHANGE_EVT*/ {BTA_AV_ROLE_RES, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST } +}; + +/* state table for reconfig state */ +static const UINT8 bta_av_sst_rcfg[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* SDP_DISC_OK_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* SDP_DISC_FAIL_EVT */ {BTA_AV_FREE_SDB, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_DISC_OK_EVT */ {BTA_AV_DISC_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_DISC_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_GETCAP_OK_EVT */ {BTA_AV_GETCAP_RESULTS, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_GETCAP_FAIL_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_OPEN_OK_EVT */ {BTA_AV_RCFG_STR_OK, BTA_AV_SIGNORE, BTA_AV_OPEN_SST }, + /* STR_OPEN_FAIL_EVT */ {BTA_AV_RCFG_FAILED, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_CLOSE_EVT */ {BTA_AV_RCFG_CONNECT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_SECURITY_IND_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SUSPEND_CONT, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* STR_RECONFIG_CFM_EVT */ {BTA_AV_RCFG_CFM, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* AVDT_CONNECT_EVT */ {BTA_AV_RCFG_OPEN, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* AVDT_DISCONNECT_EVT */ {BTA_AV_RCFG_DISCNTD, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* AVDT_DELAY_RPT_EVT */ {BTA_AV_DELAY_CO, BTA_AV_SIGNORE, BTA_AV_RCFG_SST }, + /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_RCFG_SST } +}; + +/* state table for closing state */ +static const UINT8 bta_av_sst_closing[][BTA_AV_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* AP_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AP_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AP_START_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AP_STOP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* API_RECONFIG_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* API_PROTECT_REQ_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* API_PROTECT_RSP_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* API_RC_OPEN_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* SRC_DATA_READY_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* CI_SETCONFIG_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* CI_SETCONFIG_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* SDP_DISC_OK_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* SDP_DISC_FAIL_EVT */ {BTA_AV_SDP_FAILED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* STR_DISC_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_DISC_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_GETCAP_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_GETCAP_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_OPEN_OK_EVT */ {BTA_AV_DO_CLOSE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_OPEN_FAIL_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_START_OK_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_START_FAIL_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_CLOSE_EVT */ {BTA_AV_DISCONNECT_REQ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_CONFIG_IND_EVT */ {BTA_AV_SETCONFIG_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_SECURITY_IND_EVT */ {BTA_AV_SECURITY_REJ, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_SECURITY_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_WRITE_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_SUSPEND_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* STR_RECONFIG_CFM_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AVRC_TIMER_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AVDT_DISCONNECT_EVT */ {BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST }, + /* ROLE_CHANGE_EVT*/ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* AVDT_DELAY_RPT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST }, + /* ACP_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_CLOSING_SST } +}; + +/* type for state table */ +typedef const UINT8 (*tBTA_AV_SST_TBL)[BTA_AV_NUM_COLS]; + +/* state table */ +static const tBTA_AV_SST_TBL bta_av_sst_tbl[] = { + bta_av_sst_init, + bta_av_sst_incoming, + bta_av_sst_opening, + bta_av_sst_open, + bta_av_sst_rcfg, + bta_av_sst_closing +}; + + + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +static char *bta_av_sst_code(UINT8 state); +#endif + +/******************************************************************************* +** +** Function bta_av_is_rcfg_sst +** +** Description Check if stream state machine is in reconfig state. +** +** +** Returns TRUE if stream state machine is in reconfig state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_rcfg_sst (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_rcfg_sst = FALSE; + + if (p_scb != NULL) { + if (p_scb->state == BTA_AV_RCFG_SST) { + is_rcfg_sst = TRUE; + } + } + + return is_rcfg_sst; +} + +/******************************************************************************* +** +** Function bta_av_ssm_execute +** +** Description Stream state machine event handling function for AV +** +** +** Returns void +** +*******************************************************************************/ +void bta_av_ssm_execute(tBTA_AV_SCB *p_scb, UINT16 event, tBTA_AV_DATA *p_data) +{ + tBTA_AV_SST_TBL state_table; + UINT8 action; + int i, xx; + + if (p_scb == NULL) { + /* this stream is not registered */ + APPL_TRACE_EVENT("AV channel not registered"); + return; + } + + /* In case incoming connection is for VDP, we need to swap scb. */ + /* When ACP_CONNECT_EVT was received, we put first available scb to */ + /* to Incoming state. Later, when STR_CONFIG_IND_EVT is coming, we */ + /* know if it is A2DP or VDP. */ + if ((p_scb->state == BTA_AV_INIT_SST) && (event == BTA_AV_STR_CONFIG_IND_EVT)) { + for (xx = 0; xx < BTA_AV_NUM_STRS; xx++) { + if (bta_av_cb.p_scb[xx]) { + if (bta_av_cb.p_scb[xx]->state == BTA_AV_INCOMING_SST) { + bta_av_cb.p_scb[xx]->state = BTA_AV_INIT_SST; + bta_av_cb.p_scb[xx]->coll_mask = 0; + p_scb->state = BTA_AV_INCOMING_SST; + break; + } + } + } + } + +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) + APPL_TRACE_VERBOSE("AV Sevent(0x%x)=0x%x(%s) state=%d(%s)", + p_scb->hndl, event, bta_av_evt_code(event), p_scb->state, bta_av_sst_code(p_scb->state)); +#else + APPL_TRACE_VERBOSE("AV Sevent=0x%x state=%d", event, p_scb->state); +#endif + + /* look up the state table for the current state */ + state_table = bta_av_sst_tbl[p_scb->state]; + + event -= BTA_AV_FIRST_SSM_EVT; + + /* set next state */ + p_scb->state = state_table[event][BTA_AV_SNEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < BTA_AV_SACTIONS; i++) { + if ((action = state_table[event][i]) != BTA_AV_SIGNORE) { + (*p_scb->p_act_tbl[action])(p_scb, p_data); + } else { + break; + } + } + +} + +/******************************************************************************* +** +** Function bta_av_is_scb_opening +** +** Description Returns TRUE is scb is in opening state. +** +** +** Returns TRUE if scb is in opening state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_scb_opening (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_opening = FALSE; + + if (p_scb) { + if (p_scb->state == BTA_AV_OPENING_SST) { + is_opening = TRUE; + } + } + + return is_opening; +} + +/******************************************************************************* +** +** Function bta_av_is_scb_incoming +** +** Description Returns TRUE is scb is in incoming state. +** +** +** Returns TRUE if scb is in incoming state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_scb_incoming (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_incoming = FALSE; + + if (p_scb) { + if (p_scb->state == BTA_AV_INCOMING_SST) { + is_incoming = TRUE; + } + } + + return is_incoming; +} + +/******************************************************************************* +** +** Function bta_av_set_scb_sst_init +** +** Description Set SST state to INIT. +** Use this function to change SST outside of state machine. +** +** Returns None +** +*******************************************************************************/ +void bta_av_set_scb_sst_init (tBTA_AV_SCB *p_scb) +{ + if (p_scb) { + p_scb->state = BTA_AV_INIT_SST; + } +} + +/******************************************************************************* +** +** Function bta_av_is_scb_init +** +** Description Returns TRUE is scb is in init state. +** +** +** Returns TRUE if scb is in incoming state. +** +*******************************************************************************/ +BOOLEAN bta_av_is_scb_init (tBTA_AV_SCB *p_scb) +{ + BOOLEAN is_init = FALSE; + + if (p_scb) { + if (p_scb->state == BTA_AV_INIT_SST) { + is_init = TRUE; + } + } + + return is_init; +} + +/******************************************************************************* +** +** Function bta_av_set_scb_sst_incoming +** +** Description Set SST state to incoming. +** Use this function to change SST outside of state machine. +** +** Returns None +** +*******************************************************************************/ +void bta_av_set_scb_sst_incoming (tBTA_AV_SCB *p_scb) +{ + if (p_scb) { + p_scb->state = BTA_AV_INCOMING_SST; + } +} + +/***************************************************************************** +** Debug Functions +*****************************************************************************/ +#if (defined(BTA_AV_DEBUG) && BTA_AV_DEBUG == TRUE) +/******************************************************************************* +** +** Function bta_av_sst_code +** +** Description +** +** Returns char * +** +*******************************************************************************/ +static char *bta_av_sst_code(UINT8 state) +{ + switch (state) { + case BTA_AV_INIT_SST: return "INIT"; + case BTA_AV_INCOMING_SST: return "INCOMING"; + case BTA_AV_OPENING_SST: return "OPENING"; + case BTA_AV_OPEN_SST: return "OPEN"; + case BTA_AV_RCFG_SST: return "RCFG"; + case BTA_AV_CLOSING_SST: return "CLOSING"; + default: return "unknown"; + } +} + +#endif +#endif /* BTA_AV_INCLUDED */ diff --git a/components/bt/bluedroid/bta/dm/bta_dm_act.c b/components/bt/bluedroid/bta/dm/bta_dm_act.c index ba2ecdaa83..6b21004a9c 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_act.c @@ -65,7 +65,9 @@ static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data); static void bta_dm_policy_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr); /* Extended Inquiry Response */ +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data); +#endif /* (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) */ static void bta_dm_set_eir (char *local_name); @@ -2714,6 +2716,7 @@ static UINT8 bta_dm_authentication_complete_cback(BD_ADDR bd_addr, DEV_CLASS dev return BTM_SUCCESS; } +#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) /******************************************************************************* ** ** Function bta_dm_sp_cback @@ -2868,6 +2871,7 @@ static UINT8 bta_dm_sp_cback (tBTM_SP_EVT event, tBTM_SP_EVT_DATA *p_data) APPL_TRACE_EVENT("dm status: %d", status); return status; } +#endif /* (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) */ /******************************************************************************* ** @@ -4108,7 +4112,7 @@ static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_D memset(&sec_event, 0, sizeof(tBTA_DM_SEC)); switch (event) { case BTM_LE_IO_REQ_EVT: -#if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) + // #if (BTM_LOCAL_IO_CAPS != BTM_IO_CAP_NONE) bta_dm_co_ble_io_req(bda, &p_data->io_req.io_cap, @@ -4117,7 +4121,7 @@ static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_D &p_data->io_req.max_key_size, &p_data->io_req.init_keys, &p_data->io_req.resp_keys); -#endif + // #endif #if BTM_OOB_INCLUDED == FALSE status = BTM_SUCCESS; #endif diff --git a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c index 92274247c6..e122177b87 100644 --- a/components/bt/bluedroid/bta/dm/bta_dm_cfg.c +++ b/components/bt/bluedroid/bta/dm/bta_dm_cfg.c @@ -152,6 +152,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] #endif }; +#define BTA_DM_PM_SPEC_TO_OFFSET (197) /* timeout offset to avoid conflict with other bluedroid host */ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { /* AG : 0 */ { @@ -160,15 +161,15 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ + {{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_RETRY, 7000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + {{BTA_DM_PM_RETRY, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } }, @@ -179,15 +180,15 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */ + {{BTA_DM_PM_PARK, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */ - {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */ + {{BTA_DM_PM_PARK, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + {{BTA_DM_PM_RETRY, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } }, @@ -198,13 +199,13 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_SNIFF, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF, 1000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF, 1000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } @@ -217,13 +218,13 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR3), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_HD_IDLE_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_SNIFF_HD_ACTIVE_IDX, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } @@ -236,13 +237,13 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } @@ -255,14 +256,14 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR1), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF_HH_OPEN_IDX, BTA_DM_PM_HH_OPEN_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close, used for HH suspend */ - {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ - {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ + {{BTA_DM_PM_SNIFF_HH_IDLE_IDX, BTA_DM_PM_HH_IDLE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_HH_ACTIVE_IDX, BTA_DM_PM_HH_ACTIVE_DELAY + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } }, @@ -280,7 +281,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } @@ -299,7 +300,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, BTA_FTS_OPS_IDLE_TO_SNIFF_DELAY_MS + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } @@ -312,7 +313,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ @@ -337,7 +338,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } @@ -356,7 +357,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ @@ -370,15 +371,15 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ - {{BTA_DM_PM_SNIFF3, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ - {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ - {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF3, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ + {{BTA_DM_PM_SNIFF, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ + {{BTA_DM_PM_SNIFF, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ - {{BTA_DM_PM_RETRY, 7000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + {{BTA_DM_PM_RETRY, 7000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } }, @@ -389,13 +390,13 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF, 3000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ + {{BTA_DM_PM_SNIFF, 3000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF4, 3000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF4, 3000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } @@ -409,18 +410,18 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { (BTA_DM_PM_SSR2), /* the SSR entry */ #endif { - {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open active */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close */ - {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ + {{BTA_DM_PM_SNIFF_A2DP_IDX, 10000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ #if defined(AMP_INCLUDED) && (AMP_INCLUDED == TRUE) {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */ #endif - {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + {{BTA_DM_PM_RETRY, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } } /* GATTS : 14 */ @@ -441,7 +442,7 @@ tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { #if defined(AMP_INCLUDED) && (AMP_INCLUDED == TRUE) {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* amp */ #endif - {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ + {{BTA_DM_PM_RETRY, 5000 + BTA_DM_PM_SPEC_TO_OFFSET}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ } } diff --git a/components/bt/bluedroid/bta/include/bta_ar_api.h b/components/bt/bluedroid/bta/include/bta_ar_api.h new file mode 100644 index 0000000000..af8ea535ef --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_ar_api.h @@ -0,0 +1,140 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the public interface file for the simulatenous advanced + * audio/video streaming (AV) source and sink of BTA, Broadcom's Bluetooth + * application layer for mobile phones. + * + ******************************************************************************/ +#ifndef BTA_AR_API_H +#define BTA_AR_API_H + +#include "avdt_api.h" +#include "avct_api.h" +#include "avrc_api.h" +#include "sdp_api.h" +#include "bta_av_api.h" +#include "bta_sys.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/* This event signal to AR user that other profile is connected */ +#define BTA_AR_AVDT_CONN_EVT (AVDT_MAX_EVT + 1) + +/******************************************************************************* +** +** Function bta_ar_init +** +** Description This function is called from bta_sys_init(). +** to initialize the control block +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_init(void); + +/******************************************************************************* +** +** Function bta_ar_reg_avdt +** +** Description This function is called to register to AVDTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_reg_avdt(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback, tBTA_SYS_ID sys_id); + +/******************************************************************************* +** +** Function bta_ar_dereg_avdt +** +** Description This function is called to de-register from AVDTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_dereg_avdt(tBTA_SYS_ID sys_id); + +/******************************************************************************* +** +** Function bta_ar_avdt_conn +** +** Description This function is called to let ar know that some AVDTP profile +** is connected for this sys_id. +** If the other sys modules started a timer for PENDING_EVT, +** the timer can be stopped now. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_avdt_conn(tBTA_SYS_ID sys_id, BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function bta_ar_reg_avct +** +** Description This function is called to register to AVCTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_reg_avct(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask, tBTA_SYS_ID sys_id); + +/******************************************************************************* +** +** Function bta_ar_dereg_avct +** +** Description This function is called to deregister from AVCTP. +** +** Returns void +** +*******************************************************************************/ +extern void bta_ar_dereg_avct(tBTA_SYS_ID sys_id); + +/****************************************************************************** +** +** Function bta_ar_reg_avrc +** +** Description This function is called to register an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +extern void bta_ar_reg_avrc(UINT16 service_uuid, char *p_service_name, + char *p_provider_name, UINT16 categories, tBTA_SYS_ID sys_id); + +/****************************************************************************** +** +** Function bta_ar_dereg_avrc +** +** Description This function is called to de-register/delete an SDP record for AVRCP. +** +** Returns void +** +******************************************************************************/ +extern void bta_ar_dereg_avrc(UINT16 service_uuid, tBTA_SYS_ID sys_id); + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AR_API_H */ diff --git a/components/bt/bluedroid/bta/include/bta_av_api.h b/components/bt/bluedroid/bta/include/bta_av_api.h new file mode 100644 index 0000000000..683b673693 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_av_api.h @@ -0,0 +1,808 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the public interface file for the advanced audio/video streaming + * (AV) subsystem of BTA, Broadcom's Bluetooth application layer for mobile + * phones. + * + ******************************************************************************/ +#ifndef BTA_AV_API_H +#define BTA_AV_API_H + +#include "avrc_api.h" +#include "avdt_api.h" +#include "a2d_api.h" +#include "bta_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ +/* Set to TRUE if seperate authorization prompt desired for AVCTP besides A2DP authorization */ +/* Typically FALSE when AVRCP is used in conjunction with A2DP */ +#ifndef BTA_AV_WITH_AVCTP_AUTHORIZATION +#define BTA_AV_WITH_AVCTP_AUTHORIZATION FALSE +#endif + +/* AV status values */ +#define BTA_AV_SUCCESS 0 /* successful operation */ +#define BTA_AV_FAIL 1 /* generic failure */ +#define BTA_AV_FAIL_SDP 2 /* service not found */ +#define BTA_AV_FAIL_STREAM 3 /* stream connection failed */ +#define BTA_AV_FAIL_RESOURCES 4 /* no resources */ +#define BTA_AV_FAIL_ROLE 5 /* failed due to role management related issues */ +#define BTA_AV_FAIL_GET_CAP 6 /* get capability failed due to no SEP availale on the peer */ + +typedef UINT8 tBTA_AV_STATUS; + +/* AV features masks */ +#define BTA_AV_FEAT_RCTG 0x0001 /* remote control target */ +#define BTA_AV_FEAT_RCCT 0x0002 /* remote control controller */ +#define BTA_AV_FEAT_PROTECT 0x0004 /* streaming media contect protection */ +#define BTA_AV_FEAT_VENDOR 0x0008 /* remote control vendor dependent commands */ +#define BTA_AV_FEAT_REPORT 0x0020 /* use reporting service for VDP */ +#define BTA_AV_FEAT_METADATA 0x0040 /* remote control Metadata Transfer command/response */ +#define BTA_AV_FEAT_MULTI_AV 0x0080 /* use multi-av, if controller supports it */ +#define BTA_AV_FEAT_BROWSE 0x0010 /* use browsing channel */ +#define BTA_AV_FEAT_MASTER 0x0100 /* stream only as master role */ +#define BTA_AV_FEAT_ADV_CTRL 0x0200 /* remote control Advanced Control command/response */ +#define BTA_AV_FEAT_DELAY_RPT 0x0400 /* allow delay reporting */ +#define BTA_AV_FEAT_ACP_START 0x0800 /* start stream when 2nd SNK was accepted */ + +/* Internal features */ +#define BTA_AV_FEAT_NO_SCO_SSPD 0x8000 /* Do not suspend av streaming as to AG events(SCO or Call) */ + +typedef UINT16 tBTA_AV_FEAT; + +/* AV channel values */ +#define BTA_AV_CHNL_MSK 0xC0 +#define BTA_AV_CHNL_AUDIO 0x40 /* audio channel */ +#define BTA_AV_CHNL_VIDEO 0x80 /* video channel */ +typedef UINT8 tBTA_AV_CHNL; + + +#define BTA_AV_HNDL_MSK 0x3F +typedef UINT8 tBTA_AV_HNDL; +/* handle index to mask */ +#define BTA_AV_HNDL_TO_MSK(h) ((UINT8)(1 << (h))) + +/* tBTA_AV_HNDL to mask */ +#define BTA_AV_HNDL_TYPE_TO_MSK(h) ((UINT8)(1 << (h&BTA_AV_HNDL_MSK))) + +/* offset of codec type in codec info byte array */ +#define BTA_AV_CODEC_TYPE_IDX AVDT_CODEC_TYPE_INDEX /* 2 */ + + + +/* maximum number of streams created: 1 for audio, 1 for video */ +#ifndef BTA_AV_NUM_STRS +#define BTA_AV_NUM_STRS 2 +#endif + +#ifndef BTA_AV_MAX_SEPS +#define BTA_AV_MAX_SEPS 2 +#endif + +#ifndef BTA_AV_MAX_A2DP_MTU +/*#define BTA_AV_MAX_A2DP_MTU 668 //224 (DM5) * 3 - 4(L2CAP header) */ +#define BTA_AV_MAX_A2DP_MTU 1008 +#endif + +#ifndef BTA_AV_MAX_VDP_MTU +#define BTA_AV_MAX_VDP_MTU 1008 +#endif + + +/* codec type */ +#define BTA_AV_CODEC_SBC A2D_MEDIA_CT_SBC /* SBC media codec type */ +#define BTA_AV_CODEC_M12 A2D_MEDIA_CT_M12 /* MPEG-1, 2 Audio media codec type */ +#define BTA_AV_CODEC_M24 A2D_MEDIA_CT_M24 /* MPEG-2, 4 AAC media codec type */ +#define BTA_AV_CODEC_ATRAC A2D_MEDIA_CT_ATRAC /* ATRAC family media codec type */ +#define BTA_AV_CODEC_H263_P0 VDP_MEDIA_CT_H263_P0 /* H.263 baseline (profile 0) */ +#define BTA_AV_CODEC_MPEG4 VDP_MEDIA_CT_MPEG4 /* MPEG-4 Visual Simple Profile */ +#define BTA_AV_CODEC_H263_P3 VDP_MEDIA_CT_H263_P3 /* H.263 profile 3 */ +#define BTA_AV_CODEC_H263_P8 VDP_MEDIA_CT_H263_P8 /* H.263 profile 8 */ +#define BTA_AV_CODEC_VEND VDP_MEDIA_CT_VEND /* Non-VDP */ + +typedef UINT8 tBTA_AV_CODEC; + +/* Company ID in BT assigned numbers */ +#define BTA_AV_BT_VENDOR_ID VDP_BT_VENDOR_ID /* Broadcom Corporation */ + +/* vendor specific codec ID */ +#define BTA_AV_CODEC_ID_H264 VDP_CODEC_ID_H264 /* Non-VDP codec ID - H.264 */ +#define BTA_AV_CODEC_ID_IMG VDP_CODEC_ID_IMG /* Non-VDP codec ID - images/slideshow */ + +/* operation id list for BTA_AvRemoteCmd */ +#define BTA_AV_RC_SELECT AVRC_ID_SELECT /* select */ +#define BTA_AV_RC_UP AVRC_ID_UP /* up */ +#define BTA_AV_RC_DOWN AVRC_ID_DOWN /* down */ +#define BTA_AV_RC_LEFT AVRC_ID_LEFT /* left */ +#define BTA_AV_RC_RIGHT AVRC_ID_RIGHT /* right */ +#define BTA_AV_RC_RIGHT_UP AVRC_ID_RIGHT_UP /* right-up */ +#define BTA_AV_RC_RIGHT_DOWN AVRC_ID_RIGHT_DOWN /* right-down */ +#define BTA_AV_RC_LEFT_UP AVRC_ID_LEFT_UP /* left-up */ +#define BTA_AV_RC_LEFT_DOWN AVRC_ID_LEFT_DOWN /* left-down */ +#define BTA_AV_RC_ROOT_MENU AVRC_ID_ROOT_MENU /* root menu */ +#define BTA_AV_RC_SETUP_MENU AVRC_ID_SETUP_MENU /* setup menu */ +#define BTA_AV_RC_CONT_MENU AVRC_ID_CONT_MENU /* contents menu */ +#define BTA_AV_RC_FAV_MENU AVRC_ID_FAV_MENU /* favorite menu */ +#define BTA_AV_RC_EXIT AVRC_ID_EXIT /* exit */ +#define BTA_AV_RC_0 AVRC_ID_0 /* 0 */ +#define BTA_AV_RC_1 AVRC_ID_1 /* 1 */ +#define BTA_AV_RC_2 AVRC_ID_2 /* 2 */ +#define BTA_AV_RC_3 AVRC_ID_3 /* 3 */ +#define BTA_AV_RC_4 AVRC_ID_4 /* 4 */ +#define BTA_AV_RC_5 AVRC_ID_5 /* 5 */ +#define BTA_AV_RC_6 AVRC_ID_6 /* 6 */ +#define BTA_AV_RC_7 AVRC_ID_7 /* 7 */ +#define BTA_AV_RC_8 AVRC_ID_8 /* 8 */ +#define BTA_AV_RC_9 AVRC_ID_9 /* 9 */ +#define BTA_AV_RC_DOT AVRC_ID_DOT /* dot */ +#define BTA_AV_RC_ENTER AVRC_ID_ENTER /* enter */ +#define BTA_AV_RC_CLEAR AVRC_ID_CLEAR /* clear */ +#define BTA_AV_RC_CHAN_UP AVRC_ID_CHAN_UP /* channel up */ +#define BTA_AV_RC_CHAN_DOWN AVRC_ID_CHAN_DOWN /* channel down */ +#define BTA_AV_RC_PREV_CHAN AVRC_ID_PREV_CHAN /* previous channel */ +#define BTA_AV_RC_SOUND_SEL AVRC_ID_SOUND_SEL /* sound select */ +#define BTA_AV_RC_INPUT_SEL AVRC_ID_INPUT_SEL /* input select */ +#define BTA_AV_RC_DISP_INFO AVRC_ID_DISP_INFO /* display information */ +#define BTA_AV_RC_HELP AVRC_ID_HELP /* help */ +#define BTA_AV_RC_PAGE_UP AVRC_ID_PAGE_UP /* page up */ +#define BTA_AV_RC_PAGE_DOWN AVRC_ID_PAGE_DOWN /* page down */ +#define BTA_AV_RC_POWER AVRC_ID_POWER /* power */ +#define BTA_AV_RC_VOL_UP AVRC_ID_VOL_UP /* volume up */ +#define BTA_AV_RC_VOL_DOWN AVRC_ID_VOL_DOWN /* volume down */ +#define BTA_AV_RC_MUTE AVRC_ID_MUTE /* mute */ +#define BTA_AV_RC_PLAY AVRC_ID_PLAY /* play */ +#define BTA_AV_RC_STOP AVRC_ID_STOP /* stop */ +#define BTA_AV_RC_PAUSE AVRC_ID_PAUSE /* pause */ +#define BTA_AV_RC_RECORD AVRC_ID_RECORD /* record */ +#define BTA_AV_RC_REWIND AVRC_ID_REWIND /* rewind */ +#define BTA_AV_RC_FAST_FOR AVRC_ID_FAST_FOR /* fast forward */ +#define BTA_AV_RC_EJECT AVRC_ID_EJECT /* eject */ +#define BTA_AV_RC_FORWARD AVRC_ID_FORWARD /* forward */ +#define BTA_AV_RC_BACKWARD AVRC_ID_BACKWARD /* backward */ +#define BTA_AV_RC_ANGLE AVRC_ID_ANGLE /* angle */ +#define BTA_AV_RC_SUBPICT AVRC_ID_SUBPICT /* subpicture */ +#define BTA_AV_RC_F1 AVRC_ID_F1 /* F1 */ +#define BTA_AV_RC_F2 AVRC_ID_F2 /* F2 */ +#define BTA_AV_RC_F3 AVRC_ID_F3 /* F3 */ +#define BTA_AV_RC_F4 AVRC_ID_F4 /* F4 */ +#define BTA_AV_RC_F5 AVRC_ID_F5 /* F5 */ +#define BTA_AV_VENDOR AVRC_ID_VENDOR /* vendor unique */ + +typedef UINT8 tBTA_AV_RC; + +/* state flag for pass through command */ +#define BTA_AV_STATE_PRESS AVRC_STATE_PRESS /* key pressed */ +#define BTA_AV_STATE_RELEASE AVRC_STATE_RELEASE /* key released */ + +typedef UINT8 tBTA_AV_STATE; + +/* command codes for BTA_AvVendorCmd */ +#define BTA_AV_CMD_CTRL AVRC_CMD_CTRL +#define BTA_AV_CMD_STATUS AVRC_CMD_STATUS +#define BTA_AV_CMD_SPEC_INQ AVRC_CMD_SPEC_INQ +#define BTA_AV_CMD_NOTIF AVRC_CMD_NOTIF +#define BTA_AV_CMD_GEN_INQ AVRC_CMD_GEN_INQ + +typedef UINT8 tBTA_AV_CMD; + +/* response codes for BTA_AvVendorRsp */ +#define BTA_AV_RSP_NOT_IMPL AVRC_RSP_NOT_IMPL +#define BTA_AV_RSP_ACCEPT AVRC_RSP_ACCEPT +#define BTA_AV_RSP_REJ AVRC_RSP_REJ +#define BTA_AV_RSP_IN_TRANS AVRC_RSP_IN_TRANS +#define BTA_AV_RSP_IMPL_STBL AVRC_RSP_IMPL_STBL +#define BTA_AV_RSP_CHANGED AVRC_RSP_CHANGED +#define BTA_AV_RSP_INTERIM AVRC_RSP_INTERIM + +typedef UINT8 tBTA_AV_CODE; + +/* error codes for BTA_AvProtectRsp */ +#define BTA_AV_ERR_NONE A2D_SUCCESS /* Success, no error */ +#define BTA_AV_ERR_BAD_STATE AVDT_ERR_BAD_STATE /* Message cannot be processed in this state */ +#define BTA_AV_ERR_RESOURCE AVDT_ERR_RESOURCE /* Insufficient resources */ +#define BTA_AV_ERR_BAD_CP_TYPE A2D_BAD_CP_TYPE /* The requested Content Protection Type is not supported */ +#define BTA_AV_ERR_BAD_CP_FORMAT A2D_BAD_CP_FORMAT /* The format of Content Protection Data is not correct */ + +typedef UINT8 tBTA_AV_ERR; + + +/* AV callback events */ +#define BTA_AV_ENABLE_EVT 0 /* AV enabled */ +#define BTA_AV_REGISTER_EVT 1 /* registered to AVDT */ +#define BTA_AV_OPEN_EVT 2 /* connection opened */ +#define BTA_AV_CLOSE_EVT 3 /* connection closed */ +#define BTA_AV_START_EVT 4 /* stream data transfer started */ +#define BTA_AV_STOP_EVT 5 /* stream data transfer stopped */ +#define BTA_AV_PROTECT_REQ_EVT 6 /* content protection request */ +#define BTA_AV_PROTECT_RSP_EVT 7 /* content protection response */ +#define BTA_AV_RC_OPEN_EVT 8 /* remote control channel open */ +#define BTA_AV_RC_CLOSE_EVT 9 /* remote control channel closed */ +#define BTA_AV_REMOTE_CMD_EVT 10 /* remote control command */ +#define BTA_AV_REMOTE_RSP_EVT 11 /* remote control response */ +#define BTA_AV_VENDOR_CMD_EVT 12 /* vendor dependent remote control command */ +#define BTA_AV_VENDOR_RSP_EVT 13 /* vendor dependent remote control response */ +#define BTA_AV_RECONFIG_EVT 14 /* reconfigure response */ +#define BTA_AV_SUSPEND_EVT 15 /* suspend response */ +#define BTA_AV_PENDING_EVT 16 /* incoming connection pending: + * signal channel is open and stream is not open + * after BTA_AV_SIG_TIME_VAL ms */ +#define BTA_AV_META_MSG_EVT 17 /* metadata messages */ +#define BTA_AV_REJECT_EVT 18 /* incoming connection rejected */ +#define BTA_AV_RC_FEAT_EVT 19 /* remote control channel peer supported features update */ +#define BTA_AV_MEDIA_SINK_CFG_EVT 20 /* command to configure codec */ +#define BTA_AV_MEDIA_DATA_EVT 21 /* sending data to Media Task */ +/* Max BTA event */ +#define BTA_AV_MAX_EVT 22 + + +/* function types for call-out functions */ +typedef BOOLEAN (*tBTA_AV_CO_INIT) (UINT8 *p_codec_type, UINT8 *p_codec_info, + UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index); +typedef void (*tBTA_AV_CO_DISC_RES) (tBTA_AV_HNDL hndl, UINT8 num_seps, + UINT8 num_snk, UINT8 num_src, BD_ADDR addr, UINT16 uuid_local); +typedef UINT8 (*tBTA_AV_CO_GETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, + UINT8 *p_num_protect, UINT8 *p_protect_info); +typedef void (*tBTA_AV_CO_SETCFG) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, + UINT8 num_protect, UINT8 *p_protect_info, + UINT8 t_local_sep, UINT8 avdt_handle); +typedef void (*tBTA_AV_CO_OPEN) (tBTA_AV_HNDL hndl, + tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu); +typedef void (*tBTA_AV_CO_CLOSE) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu); +typedef void (*tBTA_AV_CO_START) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr); +typedef void (*tBTA_AV_CO_STOP) (tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); +typedef void *(*tBTA_AV_CO_DATAPATH) (tBTA_AV_CODEC codec_type, + UINT32 *p_len, UINT32 *p_timestamp); +typedef void (*tBTA_AV_CO_DELAY) (tBTA_AV_HNDL hndl, UINT16 delay); + +/* the call-out functions for one stream */ +typedef struct { + tBTA_AV_CO_INIT init; + tBTA_AV_CO_DISC_RES disc_res; + tBTA_AV_CO_GETCFG getcfg; + tBTA_AV_CO_SETCFG setcfg; + tBTA_AV_CO_OPEN open; + tBTA_AV_CO_CLOSE close; + tBTA_AV_CO_START start; + tBTA_AV_CO_STOP stop; + tBTA_AV_CO_DATAPATH data; + tBTA_AV_CO_DELAY delay; +} tBTA_AV_CO_FUNCTS; + +typedef UINT8 tBTA_AV_EVT; + +/* Event associated with BTA_AV_ENABLE_EVT */ +typedef struct { + tBTA_AV_FEAT features; +} tBTA_AV_ENABLE; + +/* Event associated with BTA_AV_REGISTER_EVT */ +typedef struct { + tBTA_AV_CHNL chnl; /* audio/video */ + tBTA_AV_HNDL hndl; /* Handle associated with the stream. */ + UINT8 app_id; /* ID associated with call to BTA_AvRegister() */ + tBTA_AV_STATUS status; + tBTA_AV_CO_FUNCTS *p_bta_av_cos; +} tBTA_AV_REGISTER; + +/* data associated with BTA_AV_OPEN_EVT */ +#define BTA_AV_EDR_2MBPS 0x01 +#define BTA_AV_EDR_3MBPS 0x02 +typedef UINT8 tBTA_AV_EDR; + +typedef struct { + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + BD_ADDR bd_addr; + tBTA_AV_STATUS status; + BOOLEAN starting; + tBTA_AV_EDR edr; /* 0, if peer device does not support EDR */ + UINT8 sep; /* sep type of peer device */ +} tBTA_AV_OPEN; + +/* data associated with BTA_AV_CLOSE_EVT */ +typedef struct { + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + UINT8 disc_rsn; /* disconnection reason */ +} tBTA_AV_CLOSE; + +/* data associated with BTA_AV_START_EVT */ +typedef struct { + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + tBTA_AV_STATUS status; + BOOLEAN initiator; /* TRUE, if local device initiates the START */ + BOOLEAN suspending; +} tBTA_AV_START; + +/* data associated with BTA_AV_SUSPEND_EVT */ +typedef struct { + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + BOOLEAN initiator; /* TRUE, if local device initiates the SUSPEND */ + tBTA_AV_STATUS status; +} tBTA_AV_SUSPEND; + +/* data associated with BTA_AV_RECONFIG_EVT */ +typedef struct { + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + tBTA_AV_STATUS status; +} tBTA_AV_RECONFIG; + +/* data associated with BTA_AV_PROTECT_REQ_EVT */ +typedef struct { + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + UINT8 *p_data; + UINT16 len; +} tBTA_AV_PROTECT_REQ; + +/* data associated with BTA_AV_PROTECT_RSP_EVT */ +typedef struct { + tBTA_AV_CHNL chnl; + tBTA_AV_HNDL hndl; + UINT8 *p_data; + UINT16 len; + tBTA_AV_ERR err_code; +} tBTA_AV_PROTECT_RSP; + +/* data associated with BTA_AV_RC_OPEN_EVT */ +typedef struct { + UINT8 rc_handle; + tBTA_AV_FEAT peer_features; + BD_ADDR peer_addr; + tBTA_AV_STATUS status; +} tBTA_AV_RC_OPEN; + +/* data associated with BTA_AV_RC_CLOSE_EVT */ +typedef struct { + UINT8 rc_handle; + BD_ADDR peer_addr; +} tBTA_AV_RC_CLOSE; + +/* data associated with BTA_AV_RC_FEAT_EVT */ +typedef struct { + UINT8 rc_handle; + tBTA_AV_FEAT peer_features; +} tBTA_AV_RC_FEAT; + +/* data associated with BTA_AV_REMOTE_CMD_EVT */ +typedef struct { + UINT8 rc_handle; + tBTA_AV_RC rc_id; + tBTA_AV_STATE key_state; + UINT8 len; + UINT8 *p_data; + tAVRC_HDR hdr; /* Message header. */ + UINT8 label; +} tBTA_AV_REMOTE_CMD; + +/* data associated with BTA_AV_REMOTE_RSP_EVT */ +typedef struct { + UINT8 rc_handle; + tBTA_AV_RC rc_id; + tBTA_AV_STATE key_state; + UINT8 len; + UINT8 *p_data; + tBTA_AV_CODE rsp_code; + UINT8 label; +} tBTA_AV_REMOTE_RSP; + +/* data associated with BTA_AV_VENDOR_CMD_EVT, BTA_AV_VENDOR_RSP_EVT */ +typedef struct { + UINT8 rc_handle; + UINT16 len; /* Max vendor dependent message is 512 */ + UINT8 label; + tBTA_AV_CODE code; + UINT32 company_id; + UINT8 *p_data; +} tBTA_AV_VENDOR; + +/* data associated with BTA_AV_META_MSG_EVT */ +typedef struct { + UINT8 rc_handle; + UINT16 len; + UINT8 label; + tBTA_AV_CODE code; + UINT32 company_id; + UINT8 *p_data; + tAVRC_MSG *p_msg; +} tBTA_AV_META_MSG; + +/* data associated with BTA_AV_PENDING_EVT */ +typedef struct { + BD_ADDR bd_addr; +} tBTA_AV_PEND; + +/* data associated with BTA_AV_REJECT_EVT */ +typedef struct { + BD_ADDR bd_addr; + tBTA_AV_HNDL hndl; /* Handle associated with the stream that rejected the connection. */ +} tBTA_AV_REJECT; + + +/* union of data associated with AV callback */ +typedef union { + tBTA_AV_CHNL chnl; + tBTA_AV_ENABLE enable; + tBTA_AV_REGISTER registr; + tBTA_AV_OPEN open; + tBTA_AV_CLOSE close; + tBTA_AV_START start; + tBTA_AV_PROTECT_REQ protect_req; + tBTA_AV_PROTECT_RSP protect_rsp; + tBTA_AV_RC_OPEN rc_open; + tBTA_AV_RC_CLOSE rc_close; + tBTA_AV_REMOTE_CMD remote_cmd; + tBTA_AV_REMOTE_RSP remote_rsp; + tBTA_AV_VENDOR vendor_cmd; + tBTA_AV_VENDOR vendor_rsp; + tBTA_AV_RECONFIG reconfig; + tBTA_AV_SUSPEND suspend; + tBTA_AV_PEND pend; + tBTA_AV_META_MSG meta_msg; + tBTA_AV_REJECT reject; + tBTA_AV_RC_FEAT rc_feat; +} tBTA_AV; + +/* union of data associated with AV Media callback */ +typedef union { + BT_HDR *p_data; + UINT8 *codec_info; +} tBTA_AV_MEDIA; + + +#define BTA_AVC_PACKET_LEN AVRC_PACKET_LEN +#define BTA_VENDOR_DATA_OFFSET 6 +#define BTA_VENDOR_HEADER_LEN 4 +#define BTA_MAX_VENDOR_DEPENDENT_DATA_LEN (BTA_AVC_PACKET_LEN-BTA_VENDOR_DATA_OFFSET-BTA_VENDOR_HEADER_LEN) +#define BTA_GROUP_NAVI_MSG_OP_DATA_LEN 5 + +#define BTA_ERROR_INVALID_CMD AVRC_STS_BAD_CMD +#define BTA_ERROR_INVALID_PARAM AVRC_STS_BAD_PARAM +#define BTA_ERROR_BAD_CONTENTS AVRC_STS_NOT_FOUND +#define BTA_ERROR_INTERNAL AVRC_STS_INTERNAL_ERR + +#define BTA_AV_META_SINGLE_PACKET AVRC_PKT_SINGLE + +#define BTA_AV_CO_METADATA AVRC_CO_METADATA + +/* AV callback */ +typedef void (tBTA_AV_CBACK)(tBTA_AV_EVT event, tBTA_AV *p_data); +typedef void (tBTA_AV_DATA_CBACK)(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data); + +/* type for stream state machine action functions */ +typedef void (*tBTA_AV_ACT)(void *p_cb, void *p_data); + +/* type for registering VDP */ +typedef void (tBTA_AV_REG) (tAVDT_CS *p_cs, char *p_service_name, void *p_data); + +/* AV configuration structure */ +typedef struct { + UINT32 company_id; /* AVRCP Company ID */ + UINT16 avrc_mtu; /* AVRCP MTU at L2CAP for control channel */ + UINT16 avrc_br_mtu; /* AVRCP MTU at L2CAP for browsing channel */ + UINT16 avrc_ct_cat; /* AVRCP controller categories */ + UINT16 avrc_tg_cat; /* AVRCP target categories */ + UINT16 sig_mtu; /* AVDTP signaling channel MTU at L2CAP */ + UINT16 audio_mtu; /* AVDTP audio transport channel MTU at L2CAP */ + const UINT16 *p_audio_flush_to;/* AVDTP audio transport channel flush timeout */ + UINT16 audio_mqs; /* AVDTP audio channel max data queue size */ + UINT16 video_mtu; /* AVDTP video transport channel MTU at L2CAP */ + UINT16 video_flush_to; /* AVDTP video transport channel flush timeout */ + BOOLEAN avrc_group; /* TRUE, to accept AVRC 1.3 group nevigation command */ + UINT8 num_co_ids; /* company id count in p_meta_co_ids */ + UINT8 num_evt_ids; /* event id count in p_meta_evt_ids */ + tBTA_AV_CODE rc_pass_rsp; /* the default response code for pass through commands */ + const UINT32 *p_meta_co_ids;/* the metadata Get Capabilities response for company id */ + const UINT8 *p_meta_evt_ids;/* the the metadata Get Capabilities response for event id */ + const tBTA_AV_ACT *p_act_tbl;/* the action function table for VDP stream */ + tBTA_AV_REG *p_reg; /* action function to register VDP */ + char avrc_controller_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP controller name */ + char avrc_target_name[BTA_SERVICE_NAME_LEN]; /* Default AVRCP target name*/ +} tBTA_AV_CFG; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ + +/******************************************************************************* +** +** Function BTA_AvEnable +** +** Description Enable the advanced audio/video service. When the enable +** operation is complete the callback function will be +** called with a BTA_AV_ENABLE_EVT. This function must +** be called before other function in the AV API are +** called. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, + tBTA_AV_CBACK *p_cback); + +/******************************************************************************* +** +** Function BTA_AvDisable +** +** Description Disable the advanced audio/video service. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDisable(void); + +/******************************************************************************* +** +** Function BTA_AvRegister +** +** Description Register the audio or video service to stack. When the +** operation is complete the callback function will be +** called with a BTA_AV_REGISTER_EVT. This function must +** be called before AVDT stream is open. +** +** +** Returns void +** +*******************************************************************************/ +void BTA_AvRegister(tBTA_AV_CHNL chnl, const char *p_service_name, + UINT8 app_id, tBTA_AV_DATA_CBACK *p_data_cback, tBTA_AV_CO_FUNCTS *bta_av_cos); + +/******************************************************************************* +** +** Function BTA_AvDeregister +** +** Description Deregister the audio or video service +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDeregister(tBTA_AV_HNDL hndl); + +/******************************************************************************* +** +** Function BTA_AvOpen +** +** Description Opens an advanced audio/video connection to a peer device. +** When connection is open callback function is called +** with a BTA_AV_OPEN_EVT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvOpen(BD_ADDR bd_addr, tBTA_AV_HNDL handle, + BOOLEAN use_rc, tBTA_SEC sec_mask, UINT16 uuid); + +/******************************************************************************* +** +** Function BTA_AvClose +** +** Description Close the current streams. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvClose(tBTA_AV_HNDL handle); + +/******************************************************************************* +** +** Function BTA_AvDisconnect +** +** Description Close the connection to the address. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvDisconnect(BD_ADDR bd_addr); + +/******************************************************************************* +** +** Function BTA_AvEnable_Sink +** +** Description Enable/Disable A2DP Sink. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvEnable_Sink(int enable); + +/******************************************************************************* +** +** Function BTA_AvStart +** +** Description Start audio/video stream data transfer. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvStart(void); + +/******************************************************************************* +** +** Function BTA_AvStop +** +** Description Stop audio/video stream data transfer. +** If suspend is TRUE, this function sends AVDT suspend signal +** to the connected peer(s). +** +** Returns void +** +*******************************************************************************/ +void BTA_AvStop(BOOLEAN suspend); + +/******************************************************************************* +** +** Function BTA_AvReconfig +** +** Description Reconfigure the audio/video stream. +** If suspend is TRUE, this function tries the suspend/reconfigure +** procedure first. +** If suspend is FALSE or when suspend/reconfigure fails, +** this function closes and re-opens the AVDT connection. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvReconfig(tBTA_AV_HNDL hndl, BOOLEAN suspend, UINT8 sep_info_idx, + UINT8 *p_codec_info, UINT8 num_protect, UINT8 *p_protect_info); + +/******************************************************************************* +** +** Function BTA_AvProtectReq +** +** Description Send a content protection request. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvProtectReq(tBTA_AV_HNDL hndl, UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_AvProtectRsp +** +** Description Send a content protection response. This function must +** be called if a BTA_AV_PROTECT_REQ_EVT is received. +** This function can only be used if AV is enabled with +** feature BTA_AV_FEAT_PROTECT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvProtectRsp(tBTA_AV_HNDL hndl, UINT8 error_code, UINT8 *p_data, + UINT16 len); + +/******************************************************************************* +** +** Function BTA_AvRemoteCmd +** +** Description Send a remote control command. This function can only +** be used if AV is enabled with feature BTA_AV_FEAT_RCCT. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvRemoteCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_RC rc_id, + tBTA_AV_STATE key_state); + +/******************************************************************************* +** +** Function BTA_AvVendorCmd +** +** Description Send a vendor dependent remote control command. This +** function can only be used if AV is enabled with feature +** BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvVendorCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE cmd_code, + UINT8 *p_data, UINT16 len); + +/******************************************************************************* +** +** Function BTA_AvVendorRsp +** +** Description Send a vendor dependent remote control response. +** This function must be called if a BTA_AV_VENDOR_CMD_EVT +** is received. This function can only be used if AV is +** enabled with feature BTA_AV_FEAT_VENDOR. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvVendorRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, + UINT8 *p_data, UINT16 len, UINT32 company_id); + + +/******************************************************************************* +** +** Function BTA_AvOpenRc +** +** Description Open an AVRCP connection toward the device with the +** specified handle +** +** Returns void +** +*******************************************************************************/ +void BTA_AvOpenRc(tBTA_AV_HNDL handle); + +/******************************************************************************* +** +** Function BTA_AvCloseRc +** +** Description Close an AVRCP connection +** +** Returns void +** +*******************************************************************************/ +void BTA_AvCloseRc(UINT8 rc_handle); + +/******************************************************************************* +** +** Function BTA_AvMetaRsp +** +** Description Send a Metadata command/response. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvMetaRsp(UINT8 rc_handle, UINT8 label, tBTA_AV_CODE rsp_code, + BT_HDR *p_pkt); + +/******************************************************************************* +** +** Function BTA_AvMetaCmd +** +** Description Send a Metadata/Advanced Control command. The message contained +** in p_pkt can be composed with AVRC utility functions. +** This function can only be used if AV is enabled with feature +** BTA_AV_FEAT_METADATA. +** This message is sent only when the peer supports the TG role. +*8 The only command makes sense right now is the absolute volume command. +** +** Returns void +** +*******************************************************************************/ +void BTA_AvMetaCmd(UINT8 rc_handle, UINT8 label, tBTA_AV_CMD cmd_code, BT_HDR *p_pkt); + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AV_API_H */ diff --git a/components/bt/bluedroid/bta/include/bta_av_ci.h b/components/bt/bluedroid/bta/include/bta_av_ci.h new file mode 100644 index 0000000000..c95326f7dc --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_av_ci.h @@ -0,0 +1,73 @@ +/****************************************************************************** + * + * Copyright (C) 2005-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the interface file for advanced audio/video call-in functions. + * + ******************************************************************************/ +#ifndef BTA_AV_CI_H +#define BTA_AV_CI_H + +#include "bta_av_api.h" + +/***************************************************************************** +** Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************************************************************************* +** +** Function bta_av_ci_src_data_ready +** +** Description This function sends an event to the AV indicating that +** the phone has audio stream data ready to send and AV +** should call bta_av_co_audio_src_data_path() or +** bta_av_co_video_src_data_path(). +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_ci_src_data_ready(tBTA_AV_CHNL chnl); + +/******************************************************************************* +** +** Function bta_av_ci_setconfig +** +** Description This function must be called in response to function +** bta_av_co_audio_setconfig() or bta_av_co_video_setconfig. +** Parameter err_code is set to an AVDTP status value; +** AVDT_SUCCESS if the codec configuration is ok, +** otherwise error. +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_ci_setconfig(tBTA_AV_HNDL hndl, UINT8 err_code, + UINT8 category, UINT8 num_seid, UINT8 *p_seid, + BOOLEAN recfg_needed, UINT8 avdt_handle); + + +#ifdef __cplusplus +} +#endif + +#endif /* BTA_AV_CI_H */ diff --git a/components/bt/bluedroid/bta/include/bta_av_co.h b/components/bt/bluedroid/bta/include/bta_av_co.h new file mode 100644 index 0000000000..ce93cfbd05 --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_av_co.h @@ -0,0 +1,389 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the interface file for advanced audio/video call-out functions. + * + ******************************************************************************/ +#ifndef BTA_AV_CO_H +#define BTA_AV_CO_H + +#include "l2c_api.h" +#include "bta_av_api.h" + +/***************************************************************************** +** Constants and data types +*****************************************************************************/ + +/* TRUE to use SCMS-T content protection */ +#ifndef BTA_AV_CO_CP_SCMS_T +#define BTA_AV_CO_CP_SCMS_T FALSE +#endif + +/* the content protection IDs assigned by BT SIG */ +#define BTA_AV_CP_SCMS_T_ID 0x0002 +#define BTA_AV_CP_DTCP_ID 0x0001 + +#define BTA_AV_CP_LOSC 2 +#define BTA_AV_CP_INFO_LEN 3 + +#define BTA_AV_CP_SCMS_COPY_MASK 3 +#define BTA_AV_CP_SCMS_COPY_FREE 2 +#define BTA_AV_CP_SCMS_COPY_ONCE 1 +#define BTA_AV_CP_SCMS_COPY_NEVER 0 + +#define BTA_AV_CO_DEFAULT_AUDIO_OFFSET AVDT_MEDIA_OFFSET + +enum { + BTA_AV_CO_ST_INIT, + BTA_AV_CO_ST_IN, + BTA_AV_CO_ST_OUT, + BTA_AV_CO_ST_OPEN, + BTA_AV_CO_ST_STREAM +}; + + +/* data type for the Audio Codec Information*/ +typedef struct { + UINT16 bit_rate; /* SBC encoder bit rate in kbps */ + UINT16 bit_rate_busy; /* SBC encoder bit rate in kbps */ + UINT16 bit_rate_swampd;/* SBC encoder bit rate in kbps */ + UINT8 busy_level; /* Busy level indicating the bit-rate to be used */ + UINT8 codec_info[AVDT_CODEC_SIZE]; + UINT8 codec_type; /* Codec type */ +} tBTA_AV_AUDIO_CODEC_INFO; + +/******************************************************************************* +** +** Function bta_av_co_audio_init +** +** Description This callout function is executed by AV when it is +** started by calling BTA_AvEnable(). This function can be +** used by the phone to initialize audio paths or for other +** initialization purposes. +** +** +** Returns Stream codec and content protection capabilities info. +** +*******************************************************************************/ +extern BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, + UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index); + +/******************************************************************************* +** +** Function bta_av_co_audio_disc_res +** +** Description This callout function is executed by AV to report the +** number of stream end points (SEP) were found during the +** AVDT stream discovery process. +** +** +** Returns void. +** +*******************************************************************************/ +extern void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, + UINT8 num_snk, UINT8 num_src, BD_ADDR addr, UINT16 uuid_local); + +/******************************************************************************* +** +** Function bta_av_co_video_disc_res +** +** Description This callout function is executed by AV to report the +** number of stream end points (SEP) were found during the +** AVDT stream discovery process. +** +** +** Returns void. +** +*******************************************************************************/ +extern void bta_av_co_video_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, + UINT8 num_snk, BD_ADDR addr); + +/******************************************************************************* +** +** Function bta_av_co_audio_getconfig +** +** Description This callout function is executed by AV to retrieve the +** desired codec and content protection configuration for the +** audio stream. +** +** +** Returns Stream codec and content protection configuration info. +** +*******************************************************************************/ +extern UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, + UINT8 *p_num_protect, UINT8 *p_protect_info); + +/******************************************************************************* +** +** Function bta_av_co_video_getconfig +** +** Description This callout function is executed by AV to retrieve the +** desired codec and content protection configuration for the +** video stream. +** +** +** Returns Stream codec and content protection configuration info. +** +*******************************************************************************/ +extern UINT8 bta_av_co_video_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, + UINT8 *p_num_protect, UINT8 *p_protect_info); + +/******************************************************************************* +** +** Function bta_av_co_audio_setconfig +** +** Description This callout function is executed by AV to set the +** codec and content protection configuration of the audio stream. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, + UINT8 num_protect, UINT8 *p_protect_info, UINT8 t_local_sep, UINT8 avdt_handle); + +/******************************************************************************* +** +** Function bta_av_co_video_setconfig +** +** Description This callout function is executed by AV to set the +** codec and content protection configuration of the video stream. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, + UINT8 num_protect, UINT8 *p_protect_info); + +/******************************************************************************* +** +** Function bta_av_co_audio_open +** +** Description This function is called by AV when the audio stream connection +** is opened. +** BTA-AV maintains the MTU of A2DP streams. +** If this is the 2nd audio stream, mtu is the smaller of the 2 +** streams. +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_audio_open(tBTA_AV_HNDL hndl, + tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu); + +/******************************************************************************* +** +** Function bta_av_co_video_open +** +** Description This function is called by AV when the video stream connection +** is opened. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_open(tBTA_AV_HNDL hndl, + tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu); + +/******************************************************************************* +** +** Function bta_av_co_audio_close +** +** Description This function is called by AV when the audio stream connection +** is closed. +** BTA-AV maintains the MTU of A2DP streams. +** When one stream is closed and no other audio stream is open, +** mtu is reported as 0. +** Otherwise, the MTU remains open is reported. +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT16 mtu); + +/******************************************************************************* +** +** Function bta_av_co_video_close +** +** Description This function is called by AV when the video stream connection +** is closed. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT16 mtu); + +/******************************************************************************* +** +** Function bta_av_co_audio_start +** +** Description This function is called by AV when the audio streaming data +** transfer is started. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr); + +/******************************************************************************* +** +** Function bta_av_co_video_start +** +** Description This function is called by AV when the video streaming data +** transfer is started. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr); + +/******************************************************************************* +** +** Function bta_av_co_audio_stop +** +** Description This function is called by AV when the audio streaming data +** transfer is stopped. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_audio_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); + +/******************************************************************************* +** +** Function bta_av_co_video_stop +** +** Description This function is called by AV when the video streaming data +** transfer is stopped. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type); + +/******************************************************************************* +** +** Function bta_av_co_audio_src_data_path +** +** Description This function is called to get the next data buffer from +** the audio codec +** +** Returns NULL if data is not ready. +** Otherwise, a GKI buffer (BT_HDR*) containing the audio data. +** +*******************************************************************************/ +extern void *bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, + UINT32 *p_len, UINT32 *p_timestamp); + +/******************************************************************************* +** +** Function bta_av_co_video_src_data_path +** +** Description This function is called to get the next data buffer from +** the video codec. +** +** Returns NULL if data is not ready. +** Otherwise, a video data buffer (UINT8*). +** +*******************************************************************************/ +extern void *bta_av_co_video_src_data_path(tBTA_AV_CODEC codec_type, + UINT32 *p_len, UINT32 *p_timestamp); + +/******************************************************************************* +** +** Function bta_av_co_audio_drop +** +** Description An Audio packet is dropped. . +** It's very likely that the connected headset with this handle +** is moved far away. The implementation may want to reduce +** the encoder bit rate setting to reduce the packet size. +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_audio_drop(tBTA_AV_HNDL hndl); + +/******************************************************************************* +** +** Function bta_av_co_video_report_conn +** +** Description This function is called by AV when the reporting channel is +** opened (open=TRUE) or closed (open=FALSE). +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_report_conn (BOOLEAN open, UINT8 avdt_handle); + +/******************************************************************************* +** +** Function bta_av_co_video_report_rr +** +** Description This function is called by AV when a Receiver Report is +** received +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_report_rr (UINT32 packet_lost); + +/******************************************************************************* +** +** Function bta_av_co_audio_delay +** +** Description This function is called by AV when the audio stream connection +** needs to send the initial delay report to the connected SRC. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, UINT16 delay); + +/******************************************************************************* +** +** Function bta_av_co_video_delay +** +** Description This function is called by AV when the video stream connection +** needs to send the initial delay report to the connected SRC. +** +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_co_video_delay(tBTA_AV_HNDL hndl, UINT16 delay); + +#endif /* BTA_AV_CO_H */ diff --git a/components/bt/bluedroid/bta/include/bta_av_sbc.h b/components/bt/bluedroid/bta/include/bta_av_sbc.h new file mode 100644 index 0000000000..59778edb8d --- /dev/null +++ b/components/bt/bluedroid/bta/include/bta_av_sbc.h @@ -0,0 +1,219 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the interface to utility functions for dealing with SBC data + * frames and codec capabilities. + * + ******************************************************************************/ +#ifndef BTA_AV_SBC_H +#define BTA_AV_SBC_H + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* SBC packet header size */ +#define BTA_AV_SBC_HDR_SIZE A2D_SBC_MPL_HDR_LEN + +/******************************************************************************* +** +** Function bta_av_sbc_init_up_sample +** +** Description initialize the up sample +** +** src_sps: samples per second (source audio data) +** dst_sps: samples per second (converted audio data) +** bits: number of bits per pcm sample +** n_channels: number of channels (i.e. mono(1), stereo(2)...) +** +** Returns none +** +*******************************************************************************/ +extern void bta_av_sbc_init_up_sample (UINT32 src_sps, UINT32 dst_sps, + UINT16 bits, UINT16 n_channels); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Note: An AE reported an issue with this function. +** When called with bta_av_sbc_up_sample(src, uint8_array_dst..) +** the byte before uint8_array_dst may get overwritten. +** Using uint16_array_dst avoids the problem. +** This issue is related to endian-ness and is hard to resolve +** in a generic manner. +** **************** Please use uint16 array as dst. +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16s (16bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 4 bytes) +** dst_samples: The size of p_dst (in uint of 4 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_16s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_16m (16bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_16m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8s (8bits-stereo) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (in uint of 2 bytes) +** dst_samples: The size of p_dst (in uint of 2 bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_8s (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_up_sample_8m (8bits-mono) +** +** Description Given the source (p_src) audio data and +** source speed (src_sps, samples per second), +** This function converts it to audio data in the desired format +** +** p_src: the data buffer that holds the source audio data +** p_dst: the data buffer to hold the converted audio data +** src_samples: The number of source samples (number of bytes) +** dst_samples: The size of p_dst (number of bytes) +** +** Returns The number of bytes used in p_dst +** The number of bytes used in p_src (in *p_ret) +** +*******************************************************************************/ +extern int bta_av_sbc_up_sample_8m (void *p_src, void *p_dst, + UINT32 src_samples, UINT32 dst_samples, + UINT32 *p_ret); + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_for_cap +** +** Description Determine the preferred SBC codec configuration for the +** given codec capabilities. The function is passed the +** preferred codec configuration and the peer codec +** capabilities for the stream. The function attempts to +** match the preferred capabilities with the configuration +** as best it can. The resulting codec configuration is +** returned in the same memory used for the capabilities. +** +** Returns 0 if ok, nonzero if error. +** Codec configuration in p_cap. +** +*******************************************************************************/ +extern UINT8 bta_av_sbc_cfg_for_cap(UINT8 *p_peer, tA2D_SBC_CIE *p_cap, tA2D_SBC_CIE *p_pref); + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_in_cap +** +** Description This function checks whether an SBC codec configuration +** is allowable for the given codec capabilities. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +extern UINT8 bta_av_sbc_cfg_in_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap); + +/******************************************************************************* +** +** Function bta_av_sbc_cfg_matches_cap +** +** Description This function checks whether an SBC codec configuration +** matched with capabilities. Here we check subset. +** +** Returns 0 if ok, nonzero if error. +** +*******************************************************************************/ +extern UINT8 bta_av_sbc_cfg_matches_cap(UINT8 *p_cfg, tA2D_SBC_CIE *p_cap); + +/******************************************************************************* +** +** Function bta_av_sbc_bld_hdr +** +** Description This function builds the packet header for MPF1. +** +** Returns void +** +*******************************************************************************/ +extern void bta_av_sbc_bld_hdr(BT_HDR *p_buf, UINT16 fr_per_pkt); + +#endif /* BTA_AV_SBC_H */ + diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp.c b/components/bt/bluedroid/bta/sdp/bta_sdp.c index 9d6c9b0a26..f079d2f928 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp.c +++ b/components/bt/bluedroid/bta/sdp/bta_sdp.c @@ -23,12 +23,14 @@ ******************************************************************************/ #include - +#include "bt_target.h" #include "bta_api.h" #include "bta_sys.h" #include "bta_sdp_api.h" #include "bta_sdp_int.h" +#if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) + /***************************************************************************** ** Constants and types *****************************************************************************/ @@ -75,3 +77,5 @@ BOOLEAN bta_sdp_sm_execute(BT_HDR *p_msg) return (ret); } + +#endif /* #if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_act.c b/components/bt/bluedroid/bta/sdp/bta_sdp_act.c index 1281b50ab2..de563b56c1 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp_act.c +++ b/components/bt/bluedroid/bta/sdp/bta_sdp_act.c @@ -26,7 +26,7 @@ #include "bt_defs.h" #include #include - +#include "bt_target.h" #include "allocator.h" #include "bt_types.h" #include "gki.h" @@ -39,6 +39,7 @@ #include "btm_int.h" #include "sdp_api.h" +#if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) /***************************************************************************** ** Constants *****************************************************************************/ @@ -543,3 +544,5 @@ void bta_sdp_remove_record(tBTA_SDP_MSG *p_data) bta_sdp_cb.p_dm_cback(BTA_SDP_REMOVE_RECORD_USER_EVT, NULL, p_data->record.user_data); } } + +#endif /* #if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_api.c b/components/bt/bluedroid/bta/sdp/bta_sdp_api.c index 3969b45d8e..cbbf0f4755 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp_api.c +++ b/components/bt/bluedroid/bta/sdp/bta_sdp_api.c @@ -22,6 +22,7 @@ * ******************************************************************************/ +#include "bt_target.h" #include "bta_api.h" #include "bta_sys.h" #include "bta_sdp_api.h" @@ -31,6 +32,7 @@ // #include "port_api.h" #include "sdp_api.h" +#if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) /***************************************************************************** ** Constants *****************************************************************************/ @@ -165,3 +167,4 @@ tBTA_SDP_STATUS BTA_SdpRemoveRecordByUser(void *user_data) } +#endif /* #if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c b/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c index f9c6b019a6..bbdd8c78e9 100644 --- a/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c +++ b/components/bt/bluedroid/bta/sdp/bta_sdp_cfg.c @@ -20,12 +20,15 @@ * This file contains compile-time configurable constants for SDP Search ******************************************************************************/ +#include "bt_target.h" #include "gki.h" #include "bta_api.h" #include "bta_sdp_api.h" +#if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) + #ifndef BTA_SDP_DB_SIZE -#define BTA_SDP_DB_SIZE 4500 +#define BTA_SDP_DB_SIZE 1500 #endif static UINT8 __attribute__ ((aligned(4))) bta_sdp_db_data[BTA_SDP_DB_SIZE]; @@ -37,3 +40,5 @@ const tBTA_SDP_CFG bta_sdp_cfg = { }; tBTA_SDP_CFG *p_bta_sdp_cfg = (tBTA_SDP_CFG *) &bta_sdp_cfg; + +#endif /* #if defined(BTA_SDP_INCLUDED) && (BTA_SDP_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/core/btc_config.c b/components/bt/bluedroid/btc/core/btc_config.c new file mode 100644 index 0000000000..bd0bd03187 --- /dev/null +++ b/components/bt/bluedroid/btc/core/btc_config.c @@ -0,0 +1,439 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 +#include +#include + +#include "bt_defs.h" +#include "bt_trace.h" +#include "alarm.h" +#include "allocator.h" +#include "bdaddr.h" +#include "btc_config.h" +#include "btc_util.h" +#include "config.h" +#include "osi.h" + +#include "bt_types.h" + +static const char *CONFIG_FILE_PATH = "bt_config.conf"; +static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000; + +static void timer_config_save(void *data); + +// TODO(zachoverflow): Move these two functions out, because they are too specific for this file +// {grumpy-cat/no, monty-python/you-make-me-sad} +bool btc_get_device_type(const BD_ADDR bd_addr, int *p_device_type) +{ + if (p_device_type == NULL) { + return FALSE; + } + + bt_bdaddr_t bda; + bdcpy(bda.address, bd_addr); + + bdstr_t bd_addr_str; + bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str)); + + if (!btc_config_get_int(bd_addr_str, "DevType", p_device_type)) { + return FALSE; + } + + LOG_DEBUG("%s: Device [%s] type %d\n", __FUNCTION__, bd_addr_str, *p_device_type); + return TRUE; +} + +bool btc_get_address_type(const BD_ADDR bd_addr, int *p_addr_type) +{ + if (p_addr_type == NULL) { + return FALSE; + } + + bt_bdaddr_t bda; + bdcpy(bda.address, bd_addr); + + bdstr_t bd_addr_str; + bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str)); + + if (!btc_config_get_int(bd_addr_str, "AddrType", p_addr_type)) { + return FALSE; + } + + LOG_DEBUG("%s: Device [%s] address type %d\n", __FUNCTION__, bd_addr_str, *p_addr_type); + return TRUE; +} + +static pthread_mutex_t lock; // protects operations on |config|. +static config_t *config; +static osi_alarm_t *alarm_timer; + +// Module lifecycle functions + +bool btc_config_init(void) +{ + pthread_mutex_init(&lock, NULL); + config = config_new(CONFIG_FILE_PATH); + if (!config) { + LOG_WARN("%s unable to load config file; starting unconfigured.\n", __func__); + config = config_new_empty(); + if (!config) { + LOG_ERROR("%s unable to allocate a config object.\n", __func__); + goto error; + } + } + + if (config_save(config, CONFIG_FILE_PATH)) { + // unlink(LEGACY_CONFIG_FILE_PATH); + } + + // TODO(sharvil): use a non-wake alarm for this once we have + // API support for it. There's no need to wake the system to + // write back to disk. + alarm_timer = osi_alarm_new("btc_config", timer_config_save, NULL, CONFIG_SETTLE_PERIOD_MS); + if (!alarm_timer) { + LOG_ERROR("%s unable to create alarm.\n", __func__); + goto error; + } + + return true; + +error:; + osi_alarm_free(alarm_timer); + config_free(config); + pthread_mutex_destroy(&lock); + alarm_timer = NULL; + config = NULL; + LOG_ERROR("%s failed\n", __func__); + return false; +} + +bool btc_config_shut_down(void) +{ + btc_config_flush(); + return true; +} + +bool btc_config_clean_up(void) +{ + btc_config_flush(); + + osi_alarm_free(alarm_timer); + config_free(config); + pthread_mutex_destroy(&lock); + alarm_timer = NULL; + config = NULL; + return true; +} + +bool btc_config_has_section(const char *section) +{ + assert(config != NULL); + assert(section != NULL); + + pthread_mutex_lock(&lock); + bool ret = config_has_section(config, section); + pthread_mutex_unlock(&lock); + + return ret; +} + +bool btc_config_exist(const char *section, const char *key) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + pthread_mutex_lock(&lock); + bool ret = config_has_key(config, section, key); + pthread_mutex_unlock(&lock); + + return ret; +} + +bool btc_config_get_int(const char *section, const char *key, int *value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + assert(value != NULL); + + pthread_mutex_lock(&lock); + bool ret = config_has_key(config, section, key); + if (ret) { + *value = config_get_int(config, section, key, *value); + } + pthread_mutex_unlock(&lock); + + return ret; +} + +bool btc_config_set_int(const char *section, const char *key, int value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + pthread_mutex_lock(&lock); + config_set_int(config, section, key, value); + pthread_mutex_unlock(&lock); + + return true; +} + +bool btc_config_get_str(const char *section, const char *key, char *value, int *size_bytes) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + assert(value != NULL); + assert(size_bytes != NULL); + + pthread_mutex_lock(&lock); + const char *stored_value = config_get_string(config, section, key, NULL); + pthread_mutex_unlock(&lock); + + if (!stored_value) { + return false; + } + + strlcpy(value, stored_value, *size_bytes); + *size_bytes = strlen(value) + 1; + + return true; +} + +bool btc_config_set_str(const char *section, const char *key, const char *value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + assert(value != NULL); + + pthread_mutex_lock(&lock); + config_set_string(config, section, key, value, false); + pthread_mutex_unlock(&lock); + + return true; +} + +bool btc_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + assert(value != NULL); + assert(length != NULL); + + pthread_mutex_lock(&lock); + const char *value_str = config_get_string(config, section, key, NULL); + pthread_mutex_unlock(&lock); + + if (!value_str) { + return false; + } + + size_t value_len = strlen(value_str); + if ((value_len % 2) != 0 || *length < (value_len / 2)) { + return false; + } + + for (size_t i = 0; i < value_len; ++i) + if (!isxdigit((unsigned char)value_str[i])) { + return false; + } + + for (*length = 0; *value_str; value_str += 2, *length += 1) { + unsigned int val; + sscanf(value_str, "%02x", &val); + value[*length] = (uint8_t)(val); + } + + return true; +} + +size_t btc_config_get_bin_length(const char *section, const char *key) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + pthread_mutex_lock(&lock); + const char *value_str = config_get_string(config, section, key, NULL); + pthread_mutex_unlock(&lock); + + if (!value_str) { + return 0; + } + + size_t value_len = strlen(value_str); + return ((value_len % 2) != 0) ? 0 : (value_len / 2); +} + +bool btc_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length) +{ + const char *lookup = "0123456789abcdef"; + + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + if (length > 0) { + assert(value != NULL); + } + + char *str = (char *)osi_calloc(length * 2 + 1); + if (!str) { + return false; + } + + for (size_t i = 0; i < length; ++i) { + str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F]; + str[(i * 2) + 1] = lookup[value[i] & 0x0F]; + } + + pthread_mutex_lock(&lock); + config_set_string(config, section, key, str, false); + pthread_mutex_unlock(&lock); + + osi_free(str); + return true; +} + +const btc_config_section_iter_t *btc_config_section_begin(void) +{ + assert(config != NULL); + return (const btc_config_section_iter_t *)config_section_begin(config); +} + +const btc_config_section_iter_t *btc_config_section_end(void) +{ + assert(config != NULL); + return (const btc_config_section_iter_t *)config_section_end(config); +} + +const btc_config_section_iter_t *btc_config_section_next(const btc_config_section_iter_t *section) +{ + assert(config != NULL); + assert(section != NULL); + return (const btc_config_section_iter_t *)config_section_next((const config_section_node_t *)section); +} + +const char *btc_config_section_name(const btc_config_section_iter_t *section) +{ + assert(config != NULL); + assert(section != NULL); + return config_section_name((const config_section_node_t *)section); +} + +bool btc_config_remove(const char *section, const char *key) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + pthread_mutex_lock(&lock); + bool ret = config_remove_key(config, section, key); + pthread_mutex_unlock(&lock); + + return ret; +} + +void btc_config_save(void) +{ + assert(alarm_timer != NULL); + assert(config != NULL); + + osi_alarm_set(alarm_timer, CONFIG_SETTLE_PERIOD_MS); +} + +void btc_config_flush(void) +{ + assert(config != NULL); + assert(alarm_timer != NULL); + osi_alarm_cancel(alarm_timer); + + pthread_mutex_lock(&lock); + config_save(config, CONFIG_FILE_PATH); + pthread_mutex_unlock(&lock); +} + +int btc_config_clear(void) +{ + assert(config != NULL); + assert(alarm_timer != NULL); + + osi_alarm_cancel(alarm_timer); + + pthread_mutex_lock(&lock); + config_free(config); + + config = config_new_empty(); + if (config == NULL) { + pthread_mutex_unlock(&lock); + return false; + } + + int ret = config_save(config, CONFIG_FILE_PATH); + pthread_mutex_unlock(&lock); + return ret; +} + +static void timer_config_save(UNUSED_ATTR void *data) +{ + assert(config != NULL); + assert(alarm_timer != NULL); + + // Garbage collection process: the config file accumulates + // cached information about remote devices during regular + // inquiry scans. We remove some of these junk entries + // so the file doesn't grow indefinitely. We have to take care + // to make sure we don't remove information about bonded + // devices (hence the check for link keys). + static const size_t CACHE_MAX = 256; + const char *keys[CACHE_MAX]; + size_t num_keys = 0; + size_t total_candidates = 0; + + pthread_mutex_lock(&lock); + for (const config_section_node_t *snode = config_section_begin(config); snode != config_section_end(config); snode = config_section_next(snode)) { + const char *section = config_section_name(snode); + if (!string_is_bdaddr(section)) { + continue; + } + + if (config_has_key(config, section, "LinkKey") || + config_has_key(config, section, "LE_KEY_PENC") || + config_has_key(config, section, "LE_KEY_PID") || + config_has_key(config, section, "LE_KEY_PCSRK") || + config_has_key(config, section, "LE_KEY_LENC") || + config_has_key(config, section, "LE_KEY_LCSRK")) { + continue; + } + + if (num_keys < CACHE_MAX) { + keys[num_keys++] = section; + } + + ++total_candidates; + } + + if (total_candidates > CACHE_MAX * 2) + while (num_keys > 0) { + config_remove_section(config, keys[--num_keys]); + } + + config_save(config, CONFIG_FILE_PATH); + pthread_mutex_unlock(&lock); +} diff --git a/components/bt/bluedroid/btc/core/btc_dev.c b/components/bt/bluedroid/btc/core/btc_dev.c new file mode 100644 index 0000000000..b75100055a --- /dev/null +++ b/components/bt/bluedroid/btc/core/btc_dev.c @@ -0,0 +1,34 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 +#include "bta_api.h" +#include "btc_task.h" +#include "btc_manage.h" +#include "btc_dev.h" + +void btc_dev_call_handler(btc_msg_t *msg) +{ + btc_dev_args_t *arg = (btc_dev_args_t *)msg->arg; + + LOG_DEBUG("%s act %d\n", __FUNCTION__, msg->act); + + switch (msg->act) { + case BTC_DEV_ACT_SET_DEVICE_NAME: + BTA_DmSetDeviceName(arg->set_dev_name.device_name); + break; + default: + break; + } +} diff --git a/components/bt/bluedroid/btc/core/btc_dm.c b/components/bt/bluedroid/btc/core/btc_dm.c new file mode 100644 index 0000000000..89c5d7b0a0 --- /dev/null +++ b/components/bt/bluedroid/btc/core/btc_dm.c @@ -0,0 +1,317 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "bt_target.h" +#include +#include +#include "btc_common.h" +#include "btc_dm.h" +#include "btc_main.h" +#include "bt_trace.h" +#include "bt_target.h" +#include "btc_storage.h" +#include "bta_api.h" + + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ +#define BTA_SERVICE_ID_TO_SERVICE_MASK(id) (1 << (id)) + +/****************************************************************************** +** Static variables +******************************************************************************/ +static tBTA_SERVICE_MASK btc_enabled_services = 0; +/****************************************************************************** +** Static functions +******************************************************************************/ +/****************************************************************************** +** Externs +******************************************************************************/ +#if BTC_AV_INCLUDED +extern bt_status_t btc_av_execute_service(BOOLEAN b_enable); +extern bt_status_t btc_av_sink_execute_service(BOOLEAN b_enable); +#endif +/****************************************************************************** +** Functions +******************************************************************************/ +static void btc_dm_sec_arg_deep_free(btc_msg_t *msg) +{ + btc_dm_sec_args_t *arg = (btc_dm_sec_args_t *)(msg->arg); + if (msg->act == BTA_DM_BLE_KEY_EVT) { + osi_free(arg->sec.ble_key.p_key_value); + } +} + +void btc_dm_sec_arg_deep_copy(btc_msg_t *msg, void *dst, void *src) +{ + tBTA_DM_SEC *dst_dm_sec = (tBTA_DM_SEC *)dst; + tBTA_DM_SEC *src_dm_sec = (tBTA_DM_SEC *)src; + + if (!src_dm_sec) { + return; + } + + assert(dst_dm_sec); + memcpy(dst_dm_sec, src_dm_sec, sizeof(tBTA_DM_SEC)); + + if (msg->act == BTA_DM_BLE_KEY_EVT) { + dst_dm_sec->ble_key.p_key_value = osi_malloc(sizeof(tBTM_LE_KEY_VALUE)); + assert(src_dm_sec->ble_key.p_key_value); + assert(dst_dm_sec->ble_key.p_key_value); + memcpy(dst_dm_sec->ble_key.p_key_value, src_dm_sec->ble_key.p_key_value, sizeof(tBTM_LE_KEY_VALUE)); + } +} + +/******************************************************************************* +** +** Function btc_dm_evt +** +** Description Switches context from BTE to BTC for all DM events +** +** Returns void +** +*******************************************************************************/ + +void btc_dm_sec_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *data) +{ + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DM_SEC; + msg.act = event; + + btc_transfer_context(&msg, (btc_dm_sec_args_t *)data, sizeof(btc_dm_sec_args_t), btc_dm_sec_arg_deep_copy); +} + +static void btc_enable_bluetooth_evt(tBTA_STATUS status) +{ + if (status == BTA_SUCCESS) { + future_ready(*btc_main_get_future_p(BTC_MAIN_ENABLE_FUTURE), FUTURE_SUCCESS); + } else { + future_ready(*btc_main_get_future_p(BTC_MAIN_ENABLE_FUTURE), FUTURE_FAIL); + } +} + +static void btc_disable_bluetooth_evt(void) +{ + LOG_DEBUG("%s", __FUNCTION__); + + future_ready(*btc_main_get_future_p(BTC_MAIN_DISABLE_FUTURE), FUTURE_SUCCESS); +} + +static void btc_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl) +{ + /* Save link key, if not temporary */ + bt_bdaddr_t bd_addr; + bt_status_t status; + LOG_DEBUG("%s: bond state success %d, present %d, type%d\n", __func__, p_auth_cmpl->success, + p_auth_cmpl->key_present, p_auth_cmpl->key_type); + + bdcpy(bd_addr.address, p_auth_cmpl->bd_addr); + if ( (p_auth_cmpl->success == TRUE) && (p_auth_cmpl->key_present) ) { +#if 0 + if ((p_auth_cmpl->key_type < HCI_LKEY_TYPE_DEBUG_COMB) || + (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB) || + (p_auth_cmpl->key_type == HCI_LKEY_TYPE_CHANGED_COMB) || + (p_auth_cmpl->key_type == HCI_LKEY_TYPE_AUTH_COMB_P_256) + ) +#endif + if (1) { + bt_status_t ret; + LOG_DEBUG("%s: Storing link key. key_type=0x%x", + __FUNCTION__, p_auth_cmpl->key_type); + ret = btc_storage_add_bonded_device(&bd_addr, + p_auth_cmpl->key, p_auth_cmpl->key_type, + 16); + BTC_ASSERTC(ret == BT_STATUS_SUCCESS, "storing link key failed", ret); + } else { + LOG_DEBUG("%s: Temporary key. Not storing. key_type=0x%x", + __FUNCTION__, p_auth_cmpl->key_type); + } + } + + // Skip SDP for certain HID Devices + if (p_auth_cmpl->success) { + } else { + // Map the HCI fail reason to bt status + switch (p_auth_cmpl->fail_reason) { + case HCI_ERR_PAGE_TIMEOUT: + LOG_WARN("%s() - Pairing timeout; retrying () ...", __FUNCTION__); + return; + /* Fall-through */ + case HCI_ERR_CONNECTION_TOUT: + status = BT_STATUS_RMT_DEV_DOWN; + break; + + case HCI_ERR_PAIRING_NOT_ALLOWED: + status = BT_STATUS_AUTH_REJECTED; + break; + + case HCI_ERR_LMP_RESPONSE_TIMEOUT: + status = BT_STATUS_AUTH_FAILURE; + break; + + /* map the auth failure codes, so we can retry pairing if necessary */ + case HCI_ERR_AUTH_FAILURE: + case HCI_ERR_KEY_MISSING: + btc_storage_remove_bonded_device(&bd_addr); + case HCI_ERR_HOST_REJECT_SECURITY: + case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE: + case HCI_ERR_UNIT_KEY_USED: + case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED: + case HCI_ERR_INSUFFCIENT_SECURITY: + case HCI_ERR_PEER_USER: + case HCI_ERR_UNSPECIFIED: + LOG_DEBUG(" %s() Authentication fail reason %d", + __FUNCTION__, p_auth_cmpl->fail_reason); + /* if autopair attempts are more than 1, or not attempted */ + status = BT_STATUS_AUTH_FAILURE; + break; + default: + status = BT_STATUS_FAIL; + } + } + (void) status; +} + +tBTA_SERVICE_MASK btc_get_enabled_services_mask(void) +{ + return btc_enabled_services; +} + +void btc_clear_services_mask(void) +{ + btc_enabled_services = 0; +} + +static bt_status_t btc_in_execute_service_request(tBTA_SERVICE_ID service_id, + BOOLEAN b_enable) +{ + LOG_DEBUG("%s service_id: %d\n", __FUNCTION__, service_id); + /* Check the service_ID and invoke the profile's BT state changed API */ + switch (service_id) { +#if BTC_AV_INCLUDED + case BTA_A2DP_SOURCE_SERVICE_ID: + btc_av_execute_service(b_enable); + break; + case BTA_A2DP_SINK_SERVICE_ID: + btc_av_sink_execute_service(b_enable); + break; +#endif + default: + LOG_ERROR("%s: Unknown service being enabled\n", __FUNCTION__); + return BT_STATUS_FAIL; + } + return BT_STATUS_SUCCESS; +} + +void btc_dm_execute_service_request(BOOLEAN enable, char *p_param) +{ + btc_in_execute_service_request(*((tBTA_SERVICE_ID *)p_param), enable); +} + +bt_status_t btc_dm_enable_service(tBTA_SERVICE_ID service_id) +{ + tBTA_SERVICE_ID *p_id = &service_id; + + btc_enabled_services |= (1 << service_id); + + LOG_DEBUG("%s: current services:0x%x", __FUNCTION__, btc_enabled_services); + + btc_dm_execute_service_request(TRUE, (char *)p_id); + + return BT_STATUS_SUCCESS; +} + +bt_status_t btc_dm_disable_service(tBTA_SERVICE_ID service_id) +{ + tBTA_SERVICE_ID *p_id = &service_id; + + btc_enabled_services &= (tBTA_SERVICE_MASK)(~(1 << service_id)); + + LOG_DEBUG("%s: Current Services:0x%x", __FUNCTION__, btc_enabled_services); + + btc_dm_execute_service_request(FALSE, (char *)p_id); + + return BT_STATUS_SUCCESS; +} + +void btc_dm_sec_cb_handler(btc_msg_t *msg) +{ + btc_dm_sec_args_t *arg = (btc_dm_sec_args_t *)(msg->arg); + tBTA_DM_SEC *p_data = &(arg->sec); + // tBTA_SERVICE_MASK service_mask; + LOG_DEBUG("btc_dm_upstreams_cback ev: %d\n", msg->act); + + switch (msg->act) { + case BTA_DM_ENABLE_EVT: { + btc_clear_services_mask(); + btc_storage_load_bonded_devices(); + btc_enable_bluetooth_evt(p_data->enable.status); + break; + } + case BTA_DM_DISABLE_EVT: { + tBTA_SERVICE_MASK service_mask = btc_get_enabled_services_mask(); + for (int i = 0; i <= BTA_MAX_SERVICE_ID; i++) { + if (service_mask & + (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i))) { + btc_in_execute_service_request(i, FALSE); + } + } + btc_disable_bluetooth_evt(); + break; + } + case BTA_DM_PIN_REQ_EVT: + break; + case BTA_DM_AUTH_CMPL_EVT: + btc_dm_auth_cmpl_evt(&p_data->auth_cmpl); + break; + case BTA_DM_BOND_CANCEL_CMPL_EVT: + case BTA_DM_SP_CFM_REQ_EVT: + case BTA_DM_SP_KEY_NOTIF_EVT: + + case BTA_DM_DEV_UNPAIRED_EVT: + case BTA_DM_BUSY_LEVEL_EVT: + case BTA_DM_LINK_UP_EVT: + case BTA_DM_LINK_DOWN_EVT: + case BTA_DM_HW_ERROR_EVT: + +#if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) + case BTA_DM_BLE_KEY_EVT: + case BTA_DM_BLE_SEC_REQ_EVT: + case BTA_DM_BLE_PASSKEY_NOTIF_EVT: + case BTA_DM_BLE_PASSKEY_REQ_EVT: + case BTA_DM_BLE_NC_REQ_EVT: + case BTA_DM_BLE_OOB_REQ_EVT: + case BTA_DM_BLE_LOCAL_IR_EVT: + case BTA_DM_BLE_LOCAL_ER_EVT: + case BTA_DM_BLE_AUTH_CMPL_EVT: + case BTA_DM_LE_FEATURES_READ: + case BTA_DM_ENER_INFO_READ: +#endif + + case BTA_DM_AUTHORIZE_EVT: + case BTA_DM_SIG_STRENGTH_EVT: + case BTA_DM_SP_RMT_OOB_EVT: + case BTA_DM_SP_KEYPRESS_EVT: + case BTA_DM_ROLE_CHG_EVT: + + default: + LOG_WARN( "btc_dm_sec_cback : unhandled event (%d)\n", msg->act ); + break; + } + + btc_dm_sec_arg_deep_free(msg); +} diff --git a/components/bt/bluedroid/btc/core/btc_main.c b/components/bt/bluedroid/btc/core/btc_main.c index 8394c8a44d..d251782e40 100644 --- a/components/bt/bluedroid/btc/core/btc_main.c +++ b/components/bt/bluedroid/btc/core/btc_main.c @@ -14,8 +14,10 @@ #include "btc_task.h" #include "btc_main.h" +#include "btc_dm.h" #include "future.h" #include "esp_err.h" +#include "btc_config.h" #include "alarm.h" static future_t *main_future[BTC_MAIN_FUTURE_NUM]; @@ -28,30 +30,19 @@ future_t **btc_main_get_future_p(btc_main_future_type_t type) return &main_future[type]; } -static void btc_sec_callback(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data) -{ - switch (event) { - case BTA_DM_ENABLE_EVT: - future_ready(*btc_main_get_future_p(BTC_MAIN_ENABLE_FUTURE), FUTURE_SUCCESS); - break; - case BTA_DM_DISABLE_EVT: - future_ready(*btc_main_get_future_p(BTC_MAIN_DISABLE_FUTURE), FUTURE_SUCCESS); - break; - } -} - static void btc_enable_bluetooth(void) { - if (BTA_EnableBluetooth(btc_sec_callback) != BTA_SUCCESS) { + if (BTA_EnableBluetooth(btc_dm_sec_evt) != BTA_SUCCESS) { future_ready(*btc_main_get_future_p(BTC_MAIN_ENABLE_FUTURE), FUTURE_FAIL); - } + } } static void btc_disable_bluetooth(void) { + btc_config_shut_down(); if (BTA_DisableBluetooth() != BTA_SUCCESS) { future_ready(*btc_main_get_future_p(BTC_MAIN_DISABLE_FUTURE), FUTURE_FAIL); - } + } } void btc_init_callback(void) @@ -63,6 +54,7 @@ static void btc_init_bluetooth(void) { osi_alarm_create_mux(); osi_alarm_init(); + btc_config_init(); bte_main_boot_entry(btc_init_callback); } @@ -70,6 +62,7 @@ static void btc_init_bluetooth(void) static void btc_deinit_bluetooth(void) { bte_main_shutdown(); + btc_config_clean_up(); osi_alarm_deinit(); osi_alarm_delete_mux(); future_ready(*btc_main_get_future_p(BTC_MAIN_DEINIT_FUTURE), FUTURE_SUCCESS); diff --git a/components/bt/bluedroid/btc/core/btc_profile_queue.c b/components/bt/bluedroid/btc/core/btc_profile_queue.c new file mode 100644 index 0000000000..9d0c472dfb --- /dev/null +++ b/components/bt/bluedroid/btc/core/btc_profile_queue.c @@ -0,0 +1,172 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "bt_target.h" +#include +#include "esp_bt_main.h" +#include "bt_trace.h" +#include "bt_defs.h" +#include "btc_profile_queue.h" +#include "gki.h" +#include "list.h" +#include "allocator.h" + +#if BTC_PRF_QUEUE_INCLUDED +/******************************************************************************* +** Local type definitions +*******************************************************************************/ +/******************************************************************************* +** Static variables +*******************************************************************************/ + +static list_t *connect_queue; + +static const size_t MAX_REASONABLE_REQUESTS = 10; + +/******************************************************************************* +** Queue helper functions +*******************************************************************************/ + +static void queue_int_add(connect_node_t *p_param) +{ + if (!connect_queue) { + connect_queue = list_new(osi_free_func); + assert(connect_queue != NULL); + } + + // Sanity check to make sure we're not leaking connection requests + assert(list_length(connect_queue) < MAX_REASONABLE_REQUESTS); + + for (const list_node_t *node = list_begin(connect_queue); node != list_end(connect_queue); node = list_next(node)) { + if (((connect_node_t *)list_node(node))->uuid == p_param->uuid) { + LOG_DEBUG("%s dropping duplicate connect request for uuid: %04x", __func__, p_param->uuid); + return; + } + } + + connect_node_t *p_node = osi_malloc(sizeof(connect_node_t)); + assert(p_node != NULL); + memcpy(p_node, p_param, sizeof(connect_node_t)); + list_append(connect_queue, p_node); +} + +static void queue_int_advance() +{ + if (connect_queue && !list_is_empty(connect_queue)) { + list_remove(connect_queue, list_front(connect_queue)); + } +} + +void btc_profile_queue_handler(btc_msg_t *msg) +{ + btc_prf_que_args_t *arg = (btc_prf_que_args_t *)(msg->arg); + switch (msg->act) { + case BTC_PRF_QUE_CONNECT: + queue_int_add(&(arg->connect_node)); + break; + + case BTC_PRF_QUE_ADVANCE: + queue_int_advance(); + break; + } + + if (esp_bluedroid_get_status() == ESP_BLUEDROID_STATUS_ENABLED) { + btc_queue_connect_next(); + } +} + +/******************************************************************************* +** +** Function btc_queue_connect +** +** Description Add a new connection to the queue and trigger the next +** scheduled connection. +** +** Returns BT_STATUS_SUCCESS if successful +** +*******************************************************************************/ +bt_status_t btc_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda, btc_connect_cb_t connect_cb) +{ + btc_msg_t msg; + btc_prf_que_args_t arg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PRF_QUE; + msg.act = BTC_PRF_QUE_CONNECT; + + memset(&arg, 0, sizeof(btc_prf_que_args_t)); + memcpy(&arg.connect_node.bda, bda, sizeof(bt_bdaddr_t)); + arg.connect_node.uuid = uuid; + arg.connect_node.connect_cb = connect_cb; + + return btc_transfer_context(&msg, &arg, sizeof(btc_prf_que_args_t), NULL); +} +/******************************************************************************* +** +** Function btc_queue_advance +** +** Description Clear the queue's busy status and advance to the next +** scheduled connection. +** +** Returns void +** +*******************************************************************************/ +void btc_queue_advance(void) +{ + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_PRF_QUE; + msg.act = BTC_PRF_QUE_ADVANCE; + + btc_transfer_context(&msg, NULL, 0, NULL); +} + +// This function dispatches the next pending connect request. It is called from +// stack_manager when the stack comes up. +bt_status_t btc_queue_connect_next(void) +{ + if (!connect_queue || list_is_empty(connect_queue)) { + return BT_STATUS_FAIL; + } + + connect_node_t *p_head = list_front(connect_queue); + + // If the queue is currently busy, we return success anyway, + // since the connection has been queued... + if (p_head->busy) { + return BT_STATUS_SUCCESS; + } + + p_head->busy = true; + return p_head->connect_cb(&p_head->bda, p_head->uuid); +} + + +/******************************************************************************* +** +** Function btc_queue_release +** +** Description Free up all the queue nodes and set the queue head to NULL +** +** Returns void +** +*******************************************************************************/ +void btc_queue_release(void) +{ + list_free(connect_queue); + connect_queue = NULL; +} + +#endif /* if BTC_PRF_QUEUE_INCLUDED */ diff --git a/components/bt/bluedroid/btc/core/btc_sm.c b/components/bt/bluedroid/btc/core/btc_sm.c new file mode 100644 index 0000000000..236b24fa26 --- /dev/null +++ b/components/bt/bluedroid/btc/core/btc_sm.c @@ -0,0 +1,200 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + + +/***************************************************************************** + * + * Filename: btc_sm.c + * + * Description: Generic BTC state machine API + * + *****************************************************************************/ +#include "bt_target.h" +#include "bt_defs.h" +#include "allocator.h" +#include "btc_common.h" +#include "btc_sm.h" +#include "gki.h" + +#if BTC_SM_INCLUDED +/***************************************************************************** +** Constants & Macros +******************************************************************************/ +/***************************************************************************** +** Local type definitions +******************************************************************************/ +typedef struct { + btc_sm_state_t state; + btc_sm_handler_t *p_handlers; +} btc_sm_cb_t; + +/***************************************************************************** +** Static variables +******************************************************************************/ + +/***************************************************************************** +** Static functions +******************************************************************************/ + +/***************************************************************************** +** Externs +******************************************************************************/ + +/***************************************************************************** +** Functions +******************************************************************************/ + +/***************************************************************************** +** +** Function btc_sm_init +** +** Description Initializes the state machine with the state handlers +** The caller should ensure that the table and the corresponding +** states match. The location that 'p_handlers' points to shall +** be available until the btc_sm_shutdown API is invoked. +** +** Returns Returns a pointer to the initialized state machine handle. +** +******************************************************************************/ + +btc_sm_handle_t btc_sm_init(const btc_sm_handler_t *p_handlers, btc_sm_state_t initial_state) +{ + btc_sm_cb_t *p_cb; + + if (p_handlers == NULL) { + LOG_ERROR("%s : p_handlers is NULL", __FUNCTION__); + return NULL; + } + + p_cb = (btc_sm_cb_t *)osi_malloc(sizeof(btc_sm_cb_t)); + p_cb->state = initial_state; + p_cb->p_handlers = (btc_sm_handler_t *)p_handlers; + + /* Send BTC_SM_ENTER_EVT to the initial state */ + p_cb->p_handlers[initial_state](BTC_SM_ENTER_EVT, NULL); + + return (btc_sm_handle_t)p_cb; +} + +/***************************************************************************** +** +** Function btc_sm_shutdown +** +** Description Tears down the state machine +** +** Returns None +** +******************************************************************************/ +void btc_sm_shutdown(btc_sm_handle_t handle) +{ + btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle; + + if (p_cb == NULL) { + LOG_ERROR("%s : Invalid handle", __FUNCTION__); + return; + } + osi_free(p_cb); +} + +/***************************************************************************** +** +** Function btc_sm_get_state +** +** Description Fetches the current state of the state machine +** +** Returns Current state +** +******************************************************************************/ +btc_sm_state_t btc_sm_get_state(btc_sm_handle_t handle) +{ + btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle; + + if (p_cb == NULL) { + LOG_ERROR("%s : Invalid handle", __FUNCTION__); + return 0; + } + + return p_cb->state; +} + +/***************************************************************************** +** +** Function btc_sm_dispatch +** +** Description Dispatches the 'event' along with 'data' to the current state handler +** +** Returns BT_STATUS_SUCCESS on success +** BT_STATUS_UNHANDLED if event was not processed +** BT_STATUS_FAIL otherwise +** +******************************************************************************/ +bt_status_t btc_sm_dispatch(btc_sm_handle_t handle, btc_sm_event_t event, + void *data) +{ + bt_status_t status = BT_STATUS_SUCCESS; + + btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle; + + if (p_cb == NULL) { + LOG_ERROR("%s : Invalid handle", __FUNCTION__); + return BT_STATUS_FAIL; + } + + if (p_cb->p_handlers[p_cb->state](event, data) == FALSE) { + return BT_STATUS_UNHANDLED; + } + + return status; +} + +/***************************************************************************** +** +** Function btc_sm_change_state +** +** Description Make a transition to the new 'state'. The 'BTC_SM_EXIT_EVT' +** shall be invoked before exiting the current state. The +** 'BTC_SM_ENTER_EVT' shall be invoked before entering the new state +** +** Returns BT_STATUS_SUCCESS on success +** BT_STATUS_UNHANDLED if event was not processed +** BT_STATUS_FAIL otherwise +** +******************************************************************************/ +bt_status_t btc_sm_change_state(btc_sm_handle_t handle, btc_sm_state_t state) +{ + bt_status_t status = BT_STATUS_SUCCESS; + btc_sm_cb_t *p_cb = (btc_sm_cb_t *)handle; + + if (p_cb == NULL) { + LOG_ERROR("%s : Invalid handle", __FUNCTION__); + return BT_STATUS_FAIL; + } + + /* Send exit event to the current state */ + if (p_cb->p_handlers[p_cb->state](BTC_SM_EXIT_EVT, NULL) == FALSE) { + status = BT_STATUS_UNHANDLED; + } + + /* Change to the new state */ + p_cb->state = state; + + /* Send enter event to the new state */ + if (p_cb->p_handlers[p_cb->state](BTC_SM_ENTER_EVT, NULL) == FALSE) { + status = BT_STATUS_UNHANDLED; + } + + return status; +} + +#endif /* #if BTC_SM_INCLUDED */ diff --git a/components/bt/bluedroid/btc/core/btc_storage.c b/components/bt/bluedroid/btc/core/btc_storage.c new file mode 100644 index 0000000000..f3ae7a8b53 --- /dev/null +++ b/components/bt/bluedroid/btc/core/btc_storage.c @@ -0,0 +1,158 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "btc_storage.h" +#include "btc_util.h" +#include "osi.h" +#include "bt_trace.h" +#include "esp_system.h" +#include "bta_api.h" +#include "bdaddr.h" +#include "btc_config.h" + +/******************************************************************************* +** +** Function btc_storage_add_bonded_device +** +** Description BTIF storage API - Adds the newly bonded device to NVRAM +** along with the link-key, Key type and Pin key length +** +** Returns BT_STATUS_SUCCESS if the store was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ + +bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr, + LINK_KEY link_key, + uint8_t key_type, + uint8_t pin_length) +{ + bdstr_t bdstr; + + bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr)); + LOG_DEBUG("add to storage: Remote device:%s\n", bdstr); + + int ret = btc_config_set_int(bdstr, "LinkKeyType", (int)key_type); + ret &= btc_config_set_int(bdstr, "PinLength", (int)pin_length); + ret &= btc_config_set_bin(bdstr, "LinkKey", link_key, sizeof(LINK_KEY)); + /* write bonded info immediately */ + btc_config_flush(); + LOG_DEBUG("Storage add rslt %d\n", ret); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} + +/******************************************************************************* +** +** Function btc_in_fetch_bonded_devices +** +** Description Internal helper function to fetch the bonded devices +** from NVRAM +** +** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +static bt_status_t btc_in_fetch_bonded_devices(int add) +{ + BOOLEAN bt_linkkey_file_found = FALSE; + + for (const btc_config_section_iter_t *iter = btc_config_section_begin(); iter != btc_config_section_end(); iter = btc_config_section_next(iter)) { + const char *name = btc_config_section_name(iter); + if (!string_is_bdaddr(name)) { + continue; + } + + LOG_DEBUG("Remote device:%s\n", name); + LINK_KEY link_key; + size_t size = sizeof(link_key); + if (btc_config_get_bin(name, "LinkKey", link_key, &size)) { + int linkkey_type; + if (btc_config_get_int(name, "LinkKeyType", &linkkey_type)) { + //int pin_len; + //btc_config_get_int(name, "PinLength", &pin_len)) + bt_bdaddr_t bd_addr; + string_to_bdaddr(name, &bd_addr); + if (add) { + DEV_CLASS dev_class = {0, 0, 0}; + int cod; + int pin_length = 0; + if (btc_config_get_int(name, "DevClass", &cod)) { + uint2devclass((UINT32)cod, dev_class); + } + btc_config_get_int(name, "PinLength", &pin_length); + BTA_DmAddDevice(bd_addr.address, dev_class, link_key, 0, 0, + (UINT8)linkkey_type, 0, pin_length); + } + bt_linkkey_file_found = TRUE; + } else { + LOG_ERROR("bounded device:%s, LinkKeyType or PinLength is invalid\n", name); + } + } + if (!bt_linkkey_file_found) { + LOG_DEBUG("Remote device:%s, no link key\n", name); + } + } + return BT_STATUS_SUCCESS; +} + + +/******************************************************************************* +** +** Function btc_storage_load_bonded_devices +** +** Description BTC storage API - Loads all the bonded devices from NVRAM +** and adds to the BTA. +** Additionally, this API also invokes the adaper_properties_cb +** and remote_device_properties_cb for each of the bonded devices. +** +** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btc_storage_load_bonded_devices(void) +{ + bt_status_t status; + status = btc_in_fetch_bonded_devices(1); + LOG_DEBUG("Storage load rslt %d\n", status); + return status; +} + +/******************************************************************************* +** +** Function btc_storage_remove_bonded_device +** +** Description BTC storage API - Deletes the bonded device from NVRAM +** +** Returns BT_STATUS_SUCCESS if the deletion was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btc_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr) +{ + bdstr_t bdstr; + bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr)); + LOG_DEBUG("Add to storage: Remote device:%s\n", bdstr); + + int ret = 1; + if (btc_config_exist(bdstr, "LinkKeyType")) { + ret &= btc_config_remove(bdstr, "LinkKeyType"); + } + if (btc_config_exist(bdstr, "PinLength")) { + ret &= btc_config_remove(bdstr, "PinLength"); + } + if (btc_config_exist(bdstr, "LinkKey")) { + ret &= btc_config_remove(bdstr, "LinkKey"); + } + /* write bonded info immediately */ + btc_config_flush(); + return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; +} diff --git a/components/bt/bluedroid/btc/core/btc_task.c b/components/bt/bluedroid/btc/core/btc_task.c index 0ca5c9a42b..d576fdd762 100644 --- a/components/bt/bluedroid/btc/core/btc_task.c +++ b/components/bt/bluedroid/btc/core/btc_task.c @@ -20,11 +20,19 @@ #include "gki.h" #include "bt_defs.h" #include "btc_main.h" +#include "btc_dev.h" #include "btc_gatts.h" #include "btc_gattc.h" #include "btc_gap_ble.h" #include "btc_blufi_prf.h" +#include "btc_dm.h" #include "bta_gatt_api.h" +#if CONFIG_CLASSIC_BT_ENABLED +#include "btc_gap_bt.h" +#include "btc_profile_queue.h" +#include "btc_av.h" +#include "btc_avrc.h" +#endif /* #if CONFIG_CLASSIC_BT_ENABLED */ static xTaskHandle xBtcTaskHandle = NULL; @@ -32,16 +40,20 @@ static xQueueHandle xBtcQueue = 0; static btc_func_t profile_tab[BTC_PID_NUM] = { [BTC_PID_MAIN_INIT] = {btc_main_call_handler, NULL }, + [BTC_PID_DEV] = {btc_dev_call_handler, NULL }, [BTC_PID_GATTS] = {btc_gatts_call_handler, btc_gatts_cb_handler }, [BTC_PID_GATTC] = {btc_gattc_call_handler, btc_gattc_cb_handler }, [BTC_PID_GAP_BLE] = {btc_gap_ble_call_handler, btc_gap_ble_cb_handler }, - [BTC_PID_GAP_BT] = {NULL, NULL}, // {btc_gap_bt_call_handler, btc_gap_bt_cb_handler }, - [BTC_PID_SDP] = {NULL, NULL}, [BTC_PID_BLE_HID] = {NULL, NULL}, - [BTC_PID_BT_HID] = {NULL, NULL}, - [BTC_PID_SPP] = {NULL, NULL}, [BTC_PID_SPPLIKE] = {NULL, NULL}, [BTC_PID_BLUFI] = {btc_blufi_call_handler, btc_blufi_cb_handler }, + [BTC_PID_DM_SEC] = {NULL, btc_dm_sec_cb_handler }, +#if CONFIG_CLASSIC_BT_ENABLED + [BTC_PID_GAP_BT] = {btc_gap_bt_call_handler, NULL }, + [BTC_PID_PRF_QUE] = {btc_profile_queue_handler, NULL }, + [BTC_PID_A2DP] = {btc_a2dp_call_handler, btc_a2dp_cb_handler }, + [BTC_PID_AVRC] = {btc_avrc_call_handler, NULL }, +#endif /* #if CONFIG_CLASSIC_BT_ENABLED */ }; /***************************************************************************** diff --git a/components/bt/bluedroid/btc/core/btc_util.c b/components/bt/bluedroid/btc/core/btc_util.c new file mode 100644 index 0000000000..fdbe642293 --- /dev/null +++ b/components/bt/bluedroid/btc/core/btc_util.c @@ -0,0 +1,192 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + +/************************************************************************************ + * + * Filename: btc_util.c + * + * Description: Miscellaneous helper functions + * + * + ***********************************************************************************/ + +#include +#include +#include +#include + +#include "btc_util.h" +#include "bta_av_api.h" +#include "bt_defs.h" + +/************************************************************************************ +** Constants & Macros +************************************************************************************/ +#define ISDIGIT(a) ((a>='0') && (a<='9')) +#define ISXDIGIT(a) (((a>='0') && (a<='9'))||((a>='A') && (a<='F'))||((a>='a') && (a<='f'))) + +/************************************************************************************ +** Local type definitions +************************************************************************************/ + +/************************************************************************************ +** Static variables +************************************************************************************/ + +/************************************************************************************ +** Static functions +************************************************************************************/ + +/************************************************************************************ +** Externs +************************************************************************************/ + +/************************************************************************************ +** Functions +************************************************************************************/ + +/***************************************************************************** +** Logging helper functions +*****************************************************************************/ +const char *dump_rc_event(UINT8 event) +{ + switch (event) { + CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT) + CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT) + CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT) + CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT) + CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT) + CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT) + CASE_RETURN_STR(BTA_AV_META_MSG_EVT) + CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT) + default: + return "UNKNOWN_EVENT"; + } +} + +const char *dump_rc_notification_event_id(UINT8 event_id) +{ + switch (event_id) { + CASE_RETURN_STR(AVRC_EVT_PLAY_STATUS_CHANGE) + CASE_RETURN_STR(AVRC_EVT_TRACK_CHANGE) + CASE_RETURN_STR(AVRC_EVT_TRACK_REACHED_END) + CASE_RETURN_STR(AVRC_EVT_TRACK_REACHED_START) + CASE_RETURN_STR(AVRC_EVT_PLAY_POS_CHANGED) + CASE_RETURN_STR(AVRC_EVT_BATTERY_STATUS_CHANGE) + CASE_RETURN_STR(AVRC_EVT_SYSTEM_STATUS_CHANGE) + CASE_RETURN_STR(AVRC_EVT_APP_SETTING_CHANGE) + CASE_RETURN_STR(AVRC_EVT_VOLUME_CHANGE) + + default: + return "Unhandled Event ID"; + } +} + +const char *dump_rc_pdu(UINT8 pdu) +{ + switch (pdu) { + CASE_RETURN_STR(AVRC_PDU_LIST_PLAYER_APP_ATTR) + CASE_RETURN_STR(AVRC_PDU_LIST_PLAYER_APP_VALUES) + CASE_RETURN_STR(AVRC_PDU_GET_CUR_PLAYER_APP_VALUE) + CASE_RETURN_STR(AVRC_PDU_SET_PLAYER_APP_VALUE) + CASE_RETURN_STR(AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT) + CASE_RETURN_STR(AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT) + CASE_RETURN_STR(AVRC_PDU_INFORM_DISPLAY_CHARSET) + CASE_RETURN_STR(AVRC_PDU_INFORM_BATTERY_STAT_OF_CT) + CASE_RETURN_STR(AVRC_PDU_GET_ELEMENT_ATTR) + CASE_RETURN_STR(AVRC_PDU_GET_PLAY_STATUS) + CASE_RETURN_STR(AVRC_PDU_REGISTER_NOTIFICATION) + CASE_RETURN_STR(AVRC_PDU_REQUEST_CONTINUATION_RSP) + CASE_RETURN_STR(AVRC_PDU_ABORT_CONTINUATION_RSP) + CASE_RETURN_STR(AVRC_PDU_SET_ABSOLUTE_VOLUME) + default: + return "Unknown PDU"; + } +} + +UINT32 devclass2uint(DEV_CLASS dev_class) +{ + UINT32 cod = 0; + + if (dev_class != NULL) { + /* if COD is 0, irrespective of the device type set it to Unclassified device */ + cod = (dev_class[2]) | (dev_class[1] << 8) | (dev_class[0] << 16); + } + return cod; +} +void uint2devclass(UINT32 cod, DEV_CLASS dev_class) +{ + dev_class[2] = (UINT8)cod; + dev_class[1] = (UINT8)(cod >> 8); + dev_class[0] = (UINT8)(cod >> 16); +} + +static const UINT8 sdp_base_uuid[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB + }; + +void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t *uuid128) +{ + uint16_t uuid16_bo; + memset(uuid128, 0, sizeof(bt_uuid_t)); + + memcpy(uuid128->uu, sdp_base_uuid, MAX_UUID_SIZE); + uuid16_bo = ntohs(uuid16); + memcpy(uuid128->uu + 2, &uuid16_bo, sizeof(uint16_t)); +} + +void string_to_uuid(char *str, bt_uuid_t *p_uuid) +{ + uint32_t uuid0, uuid4; + uint16_t uuid1, uuid2, uuid3, uuid5; + + sscanf(str, "%08x-%04hx-%04hx-%04hx-%08x%04hx", + &uuid0, &uuid1, &uuid2, &uuid3, &uuid4, &uuid5); + + uuid0 = htonl(uuid0); + uuid1 = htons(uuid1); + uuid2 = htons(uuid2); + uuid3 = htons(uuid3); + uuid4 = htonl(uuid4); + uuid5 = htons(uuid5); + + memcpy(&(p_uuid->uu[0]), &uuid0, 4); + memcpy(&(p_uuid->uu[4]), &uuid1, 2); + memcpy(&(p_uuid->uu[6]), &uuid2, 2); + memcpy(&(p_uuid->uu[8]), &uuid3, 2); + memcpy(&(p_uuid->uu[10]), &uuid4, 4); + memcpy(&(p_uuid->uu[14]), &uuid5, 2); + + return; + +} + +void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str) +{ + uint32_t uuid0, uuid4; + uint16_t uuid1, uuid2, uuid3, uuid5; + + memcpy(&uuid0, &(p_uuid->uu[0]), 4); + memcpy(&uuid1, &(p_uuid->uu[4]), 2); + memcpy(&uuid2, &(p_uuid->uu[6]), 2); + memcpy(&uuid3, &(p_uuid->uu[8]), 2); + memcpy(&uuid4, &(p_uuid->uu[10]), 4); + memcpy(&uuid5, &(p_uuid->uu[14]), 2); + + sprintf((char *)str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", + ntohl(uuid0), ntohs(uuid1), + ntohs(uuid2), ntohs(uuid3), + ntohl(uuid4), ntohs(uuid5)); + return; +} diff --git a/components/bt/bluedroid/btc/include/btc_common.h b/components/bt/bluedroid/btc/include/btc_common.h new file mode 100644 index 0000000000..6224628971 --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_common.h @@ -0,0 +1,35 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BTC_COMMON_H__ +#define __BTC_COMMON_H__ + +#include "bt_trace.h" +#include "bt_types.h" +#include "osi.h" + +#define BTC_ASSERTC(cond, msg, val) if (!(cond)) { LOG_ERROR( \ + "### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);} + +#define BTC_HAL_CBACK(P_CB, P_CBACK, ...)\ + if (P_CB && P_CB->P_CBACK) { \ + LOG_INFO("HAL %s->%s", #P_CB, #P_CBACK); \ + P_CB->P_CBACK(__VA_ARGS__); \ + } \ + else { \ + BTC_ASSERTC(0, "Callback is NULL", 0); \ + } + +#endif /* __BTC_COMMON_H__ */ diff --git a/components/bt/bluedroid/btc/include/btc_config.h b/components/bt/bluedroid/btc/include/btc_config.h new file mode 100644 index 0000000000..1472cc83c4 --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_config.h @@ -0,0 +1,54 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BTC_CONFIG_H__ +#define __BTC_CONFIG_H__ + +#include +#include + +#include "bt_types.h" + +typedef struct btc_config_section_iter_t btc_config_section_iter_t; + +bool btc_config_init(void); +bool btc_config_shut_down(void); +bool btc_config_clean_up(void); + +bool btc_config_has_section(const char *section); +bool btc_config_exist(const char *section, const char *key); +bool btc_config_get_int(const char *section, const char *key, int *value); +bool btc_config_set_int(const char *section, const char *key, int value); +bool btc_config_get_str(const char *section, const char *key, char *value, int *size_bytes); +bool btc_config_set_str(const char *section, const char *key, const char *value); +bool btc_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length); +bool btc_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length); +bool btc_config_remove(const char *section, const char *key); + +size_t btc_config_get_bin_length(const char *section, const char *key); + +const btc_config_section_iter_t *btc_config_section_begin(void); +const btc_config_section_iter_t *btc_config_section_end(void); +const btc_config_section_iter_t *btc_config_section_next(const btc_config_section_iter_t *section); +const char *btc_config_section_name(const btc_config_section_iter_t *section); + +void btc_config_save(void); +void btc_config_flush(void); +int btc_config_clear(void); + +// TODO(zachoverflow): Eww...we need to move these out. These are peer specific, not config general. +bool btc_get_address_type(const BD_ADDR bd_addr, int *p_addr_type); +bool btc_get_device_type(const BD_ADDR bd_addr, int *p_device_type); + +#endif diff --git a/components/bt/bluedroid/btc/include/btc_dev.h b/components/bt/bluedroid/btc/include/btc_dev.h new file mode 100644 index 0000000000..dd2e8663a9 --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_dev.h @@ -0,0 +1,38 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BTC_DEV_H__ +#define __BTC_DEV_H__ + +#include "esp_bt_defs.h" +#include "esp_bt_device.h" +#include "btc_task.h" + +typedef enum { + BTC_DEV_ACT_SET_DEVICE_NAME +} btc_dev_act_t; + +/* btc_dev_args_t */ +typedef union { + // BTC_BT_GAP_ACT_SET_DEV_NAME + struct set_bt_dev_name_args { +#define ESP_DEV_DEVICE_NAME_MAX (32) + char device_name[ESP_DEV_DEVICE_NAME_MAX + 1]; + } set_dev_name; +} btc_dev_args_t; + +void btc_dev_call_handler(btc_msg_t *msg); + +#endif /* __BTC_DEV_H__ */ + diff --git a/components/bt/bluedroid/btc/include/btc_dm.h b/components/bt/bluedroid/btc/include/btc_dm.h new file mode 100644 index 0000000000..e397d82b4f --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_dm.h @@ -0,0 +1,40 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BTC_DM_H__ +#define __BTC_DM_H__ + +#include "btc_task.h" +#include "esp_bt_defs.h" +#include "bta_api.h" + +typedef enum { + BTC_DM_SEC_ACT +} btc_dm_sec_act_t; + +/* btc_dm_args_t */ +typedef union { + //BTC_DM_SEC_ACT + tBTA_DM_SEC sec; +} btc_dm_sec_args_t; + +// void btc_dm_call_handler(btc_msg_t *msg); +void btc_dm_sec_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *data); +void btc_dm_sec_cb_handler(btc_msg_t *msg); +void btc_dm_sec_arg_deep_copy(btc_msg_t *msg, void *dst, void *src); + +bt_status_t btc_dm_enable_service(tBTA_SERVICE_ID service_id); +bt_status_t btc_dm_disable_service(tBTA_SERVICE_ID service_id); + +#endif /* __BTC_DM_H__ */ diff --git a/components/bt/bluedroid/btc/include/btc_profile_queue.h b/components/bt/bluedroid/btc/include/btc_profile_queue.h new file mode 100644 index 0000000000..39b897e96c --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_profile_queue.h @@ -0,0 +1,55 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + +/******************************************************************************* + * + * Filename: btc_profile_queue.h + * + * Description: Bluetooth remote device connection queuing + * + *******************************************************************************/ + +#ifndef __BTC_PROFILE_QUEUE_H__ +#define __BTC_PROFILE_QUEUE_H__ + +#include "bt_defs.h" +#include "btc_task.h" + +typedef enum { + BTC_PRF_QUE_CONNECT = 0, + BTC_PRF_QUE_ADVANCE +} btc_prf_que_act_t; + +typedef bt_status_t (*btc_connect_cb_t) (bt_bdaddr_t *bda, uint16_t uuid); + +typedef struct connect_node_t { + bt_bdaddr_t bda; + uint16_t uuid; + bool busy; + btc_connect_cb_t connect_cb; +} connect_node_t; + +/* btc_prf_que_args_t */ +typedef union { + // BTC_PRF_QUE_CONNECT + connect_node_t connect_node; +} btc_prf_que_args_t; + +bt_status_t btc_queue_connect(uint16_t uuid, const bt_bdaddr_t *bda, btc_connect_cb_t connect_cb); +void btc_queue_advance(void); +bt_status_t btc_queue_connect_next(void); +void btc_queue_release(void); + +void btc_profile_queue_handler(btc_msg_t *msg); +#endif /* __BTC_PROFILE_QUEUE_H__ */ diff --git a/components/bt/bluedroid/btc/include/btc_sm.h b/components/bt/bluedroid/btc/include/btc_sm.h new file mode 100644 index 0000000000..b8e95b9900 --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_sm.h @@ -0,0 +1,115 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + + +/***************************************************************************** + * + * Filename: btc_sm.h + * + * Description: Generic BTC state machine API + * + *****************************************************************************/ + +#ifndef __BTC_SM_H__ +#define __BTC_SM_H__ + +/***************************************************************************** +** Constants & Macros +******************************************************************************/ + +/* Generic Enter/Exit state machine events */ +#define BTC_SM_ENTER_EVT 0xFFFF +#define BTC_SM_EXIT_EVT 0xFFFE + + +/***************************************************************************** +** Type definitions and return values +******************************************************************************/ +typedef UINT32 btc_sm_state_t; +typedef UINT32 btc_sm_event_t; +typedef void *btc_sm_handle_t; +typedef BOOLEAN (* btc_sm_handler_t)(btc_sm_event_t event, void *data); + + +/***************************************************************************** +** Functions +** +** NOTE: THESE APIs SHOULD BE INVOKED ONLY IN THE BTC CONTEXT +** +******************************************************************************/ + +/***************************************************************************** +** +** Function btc_sm_init +** +** Description Initializes the state machine with the state handlers +** The caller should ensure that the table and the corresponding +** states match. The location that 'p_handlers' points to shall +** be available until the btc_sm_shutdown API is invoked. +** +** Returns Returns a pointer to the initialized state machine handle. +** +******************************************************************************/ +btc_sm_handle_t btc_sm_init(const btc_sm_handler_t *p_handlers, + btc_sm_state_t initial_state); + +/***************************************************************************** +** +** Function btc_sm_shutdown +** +** Description Tears down the state machine +** +** Returns None +** +******************************************************************************/ +void btc_sm_shutdown(btc_sm_handle_t handle); + +/***************************************************************************** +** +** Function btc_sm_get_state +** +** Description Fetches the current state of the state machine +** +** Returns Current state +** +******************************************************************************/ +btc_sm_state_t btc_sm_get_state(btc_sm_handle_t handle); + +/***************************************************************************** +** +** Function btc_sm_dispatch +** +** Description Dispatches the 'event' along with 'data' to the current state handler +** +** Returns Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise +** +******************************************************************************/ +bt_status_t btc_sm_dispatch(btc_sm_handle_t handle, btc_sm_event_t event, + void *data); + +/***************************************************************************** +** +** Function btc_sm_change_state +** +** Description Make a transition to the new 'state'. The 'BTC_SM_EXIT_EVT' +** shall be invoked before exiting the current state. The +** 'BTC_SM_ENTER_EVT' shall be invoked before entering the new state +** +** +** Returns Returns BT_STATUS_OK on success, BT_STATUS_FAIL otherwise +** +******************************************************************************/ +bt_status_t btc_sm_change_state(btc_sm_handle_t handle, btc_sm_state_t state); + +#endif /* __BTC_SM_H__ */ diff --git a/components/bt/bluedroid/btc/include/btc_storage.h b/components/bt/bluedroid/btc/include/btc_storage.h new file mode 100644 index 0000000000..c2fb6ccbba --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_storage.h @@ -0,0 +1,62 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BTC_STORAGE_H__ +#define __BTC_STORAGE_H__ + +#include +#include "bt_defs.h" +#include "bt_types.h" + +/******************************************************************************* +** +** Function btc_storage_add_bonded_device +** +** Description BTC storage API - Adds the newly bonded device to NVRAM +** along with the link-key, Key type and Pin key length +** +** Returns BT_STATUS_SUCCESS if the store was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btc_storage_add_bonded_device(bt_bdaddr_t *remote_bd_addr, + LINK_KEY link_key, + uint8_t key_type, + uint8_t pin_length); + +/******************************************************************************* +** +** Function btc_storage_remove_bonded_device +** +** Description BTC storage API - Deletes the bonded device from NVRAM +** +** Returns BT_STATUS_SUCCESS if the deletion was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btc_storage_remove_bonded_device(bt_bdaddr_t *remote_bd_addr); + +/******************************************************************************* +** +** Function btc_storage_remove_bonded_device +** +** Description BTC storage API - Deletes the bonded device from NVRAM +** +** Returns BT_STATUS_SUCCESS if the deletion was successful, +** BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btc_storage_load_bonded_devices(void); + +#endif /* BTC_STORAGE_H */ diff --git a/components/bt/bluedroid/btc/include/btc_task.h b/components/bt/bluedroid/btc/include/btc_task.h index 1574dae2f3..bb89969746 100644 --- a/components/bt/bluedroid/btc/include/btc_task.h +++ b/components/bt/bluedroid/btc/include/btc_task.h @@ -16,6 +16,7 @@ #define __BTC_TASK_H__ #include +#include "bt_target.h" #include "bt_defs.h" #include "thread.h" @@ -35,16 +36,20 @@ typedef enum { typedef enum { BTC_PID_MAIN_INIT = 0, + BTC_PID_DEV, BTC_PID_GATTS, BTC_PID_GATTC, BTC_PID_GAP_BLE, - BTC_PID_GAP_BT, - BTC_PID_SDP, BTC_PID_BLE_HID, - BTC_PID_BT_HID, - BTC_PID_SPP, BTC_PID_SPPLIKE, BTC_PID_BLUFI, + BTC_PID_DM_SEC, +#if CONFIG_CLASSIC_BT_ENABLED + BTC_PID_GAP_BT, + BTC_PID_PRF_QUE, + BTC_PID_A2DP, + BTC_PID_AVRC, +#endif /* CONFIG_CLASSIC_BT_ENABLED */ BTC_PID_NUM, } btc_pid_t; //btc profile id diff --git a/components/bt/bluedroid/btc/include/btc_util.h b/components/bt/bluedroid/btc/include/btc_util.h new file mode 100644 index 0000000000..23a8fe309d --- /dev/null +++ b/components/bt/bluedroid/btc/include/btc_util.h @@ -0,0 +1,47 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BTC_UTIL_H__ +#define __BTC_UTIL_H__ + +#include +#include "bt_types.h" +#include "bt_defs.h" + +/******************************************************************************* +** Constants & Macros +********************************************************************************/ +#define CASE_RETURN_STR(const) case const: return #const; + +/******************************************************************************* +** Type definitions for callback functions +********************************************************************************/ +typedef char bdstr_t[18]; + + +/******************************************************************************* +** Functions +********************************************************************************/ +const char *dump_rc_event(UINT8 event); +const char *dump_rc_notification_event_id(UINT8 event_id); +const char *dump_rc_pdu(UINT8 pdu); + +UINT32 devclass2uint(DEV_CLASS dev_class); +void uint2devclass(UINT32 dev, DEV_CLASS dev_class); +void uuid16_to_uuid128(uint16_t uuid16, bt_uuid_t *uuid128); + +void uuid_to_string_legacy(bt_uuid_t *p_uuid, char *str); +void string_to_uuid(char *str, bt_uuid_t *p_uuid); + +#endif /* __BTC_UTIL_H__ */ diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c b/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c new file mode 100644 index 0000000000..4ee4ed3f12 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/a2dp/bta_av_co.c @@ -0,0 +1,1751 @@ +/****************************************************************************** + * + * Copyright (C) 2004-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the advanced audio/video call-out function implementation for + * BTC. + * + ******************************************************************************/ +#include "string.h" +#include "bt_target.h" +#include "a2d_api.h" +#include "a2d_sbc.h" +#include "bta_sys.h" +#include "bta_av_api.h" +#include "bta_av_co.h" +#include "bta_av_ci.h" +#include "bta_av_sbc.h" +#include "btc_media.h" +#include "btc_av_co.h" +#include "btc_util.h" + +#if BTC_AV_INCLUDED + +/***************************************************************************** + ** Constants + *****************************************************************************/ + +#define FUNC_TRACE() APPL_TRACE_DEBUG("%s", __FUNCTION__); + +/* Macro to retrieve the number of elements in a statically allocated array */ +#define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a)/sizeof((__a)[0])) + +/* MIN and MAX macros */ +#define BTA_AV_CO_MIN(X,Y) ((X) < (Y) ? (X) : (Y)) +#define BTA_AV_CO_MAX(X,Y) ((X) > (Y) ? (X) : (Y)) + +/* Macro to convert audio handle to index and vice versa */ +#define BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl) (((hndl) & (~BTA_AV_CHNL_MSK)) - 1) +#define BTA_AV_CO_AUDIO_INDX_TO_HNDL(indx) (((indx) + 1) | BTA_AV_CHNL_AUDIO) + + +/* Offsets to access codec information in SBC codec */ +#define BTA_AV_CO_SBC_FREQ_CHAN_OFF 3 +#define BTA_AV_CO_SBC_BLOCK_BAND_OFF 4 +#define BTA_AV_CO_SBC_MIN_BITPOOL_OFF 5 +#define BTA_AV_CO_SBC_MAX_BITPOOL_OFF 6 + +#define BTA_AV_CO_SBC_MAX_BITPOOL 53 + +/* SCMS-T protect info */ +const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00"; + +/* SBC SRC codec capabilities */ +const tA2D_SBC_CIE bta_av_co_sbc_caps = { + (A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ + (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */ + (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */ + (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */ + (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */ + BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */ + A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ +}; + +/* SBC SINK codec capabilities */ +const tA2D_SBC_CIE bta_av_co_sbc_sink_caps = { + (A2D_SBC_IE_SAMP_FREQ_48 | A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ + (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */ + (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */ + (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */ + (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */ + A2D_SBC_IE_MAX_BITPOOL, /* max_bitpool */ + A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ +}; + +#if !defined(BTC_AV_SBC_DEFAULT_SAMP_FREQ) +#define BTC_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_44 +#endif + +/* Default SBC codec configuration */ +const tA2D_SBC_CIE btc_av_sbc_default_config = { + BTC_AV_SBC_DEFAULT_SAMP_FREQ, /* samp_freq */ + A2D_SBC_IE_CH_MD_JOINT, /* ch_mode */ + A2D_SBC_IE_BLOCKS_16, /* block_len */ + A2D_SBC_IE_SUBBAND_8, /* num_subbands */ + A2D_SBC_IE_ALLOC_MD_L, /* alloc_mthd */ + BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */ + A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ +}; + + +/***************************************************************************** +** Local data +*****************************************************************************/ +typedef struct { + UINT8 sep_info_idx; /* local SEP index (in BTA tables) */ + UINT8 seid; /* peer SEP index (in peer tables) */ + UINT8 codec_type; /* peer SEP codec type */ + UINT8 codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */ + UINT8 num_protect; /* peer SEP number of CP elements */ + UINT8 protect_info[BTA_AV_CP_INFO_LEN]; /* peer SEP content protection info */ +} tBTA_AV_CO_SINK; + +typedef struct { + BD_ADDR addr; /* address of audio/video peer */ + tBTA_AV_CO_SINK snks[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported sinks */ + tBTA_AV_CO_SINK srcs[BTC_SV_AV_AA_SEP_INDEX]; /* array of supported srcs */ + UINT8 num_snks; /* total number of sinks at peer */ + UINT8 num_srcs; /* total number of srcs at peer */ + UINT8 num_seps; /* total number of seids at peer */ + UINT8 num_rx_snks; /* number of received sinks */ + UINT8 num_rx_srcs; /* number of received srcs */ + UINT8 num_sup_snks; /* number of supported sinks in the snks array */ + UINT8 num_sup_srcs; /* number of supported srcs in the srcs array */ + tBTA_AV_CO_SINK *p_snk; /* currently selected sink */ + tBTA_AV_CO_SINK *p_src; /* currently selected src */ + UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */ + BOOLEAN cp_active; /* current CP configuration */ + BOOLEAN acp; /* acceptor */ + BOOLEAN recfg_needed; /* reconfiguration is needed */ + BOOLEAN opened; /* opened */ + UINT16 mtu; /* maximum transmit unit size */ + UINT16 uuid_to_connect; /* uuid of peer device */ +} tBTA_AV_CO_PEER; + +typedef struct { + BOOLEAN active; + UINT8 flag; +} tBTA_AV_CO_CP; + +typedef struct { + /* Connected peer information */ + tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS]; + /* Current codec configuration - access to this variable must be protected */ + tBTC_AV_CODEC_INFO codec_cfg; + tBTC_AV_CODEC_INFO codec_cfg_setconfig; /* remote peer setconfig preference */ + + tBTA_AV_CO_CP cp; +} tBTA_AV_CO_CB; + +/* Control block instance */ +static tBTA_AV_CO_CB bta_av_co_cb; + +static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg); +static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer); +static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo); +static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink); +static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index); +static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg); +static BOOLEAN bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg); +static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index); + + + +/******************************************************************************* + ** + ** Function bta_av_co_cp_is_active + ** + ** Description Get the current configuration of content protection + ** + ** Returns TRUE if the current streaming has CP, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_cp_is_active(void) +{ + FUNC_TRACE(); + return bta_av_co_cb.cp.active; +} + +/******************************************************************************* + ** + ** Function bta_av_co_cp_get_flag + ** + ** Description Get content protection flag + ** BTA_AV_CP_SCMS_COPY_NEVER + ** BTA_AV_CP_SCMS_COPY_ONCE + ** BTA_AV_CP_SCMS_COPY_FREE + ** + ** Returns The current flag value + ** + *******************************************************************************/ +UINT8 bta_av_co_cp_get_flag(void) +{ + FUNC_TRACE(); + return bta_av_co_cb.cp.flag; +} + +/******************************************************************************* + ** + ** Function bta_av_co_cp_set_flag + ** + ** Description Set content protection flag + ** BTA_AV_CP_SCMS_COPY_NEVER + ** BTA_AV_CP_SCMS_COPY_ONCE + ** BTA_AV_CP_SCMS_COPY_FREE + ** + ** Returns TRUE if setting the SCMS flag is supported else FALSE + ** + *******************************************************************************/ +BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag) +{ + FUNC_TRACE(); + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) +#else + if (cp_flag != BTA_AV_CP_SCMS_COPY_FREE) { + return FALSE; + } +#endif + bta_av_co_cb.cp.flag = cp_flag; + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_get_peer + ** + ** Description find the peer entry for a given handle + ** + ** Returns the control block + ** + *******************************************************************************/ +static tBTA_AV_CO_PEER *bta_av_co_get_peer(tBTA_AV_HNDL hndl) +{ + UINT8 index; + FUNC_TRACE(); + + index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl); + + /* Sanity check */ + if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers)) { + APPL_TRACE_ERROR("bta_av_co_get_peer peer index out of bounds:%d", index); + return NULL; + } + + return &bta_av_co_cb.peers[index]; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_init + ** + ** Description This callout function is executed by AV when it is + ** started by calling BTA_AvRegister(). This function can be + ** used by the phone to initialize audio paths or for other + ** initialization purposes. + ** + ** + ** Returns Stream codec and content protection capabilities info. + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_num_protect, + UINT8 *p_protect_info, UINT8 index) +{ + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_init: %d", index); + + /* By default - no content protection info */ + *p_num_protect = 0; + *p_protect_info = 0; + + /* reset remote preference through setconfig */ + bta_av_co_cb.codec_cfg_setconfig.id = BTC_AV_CODEC_NONE; + + switch (index) { + case BTC_SV_AV_AA_SBC_INDEX: +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + { + UINT8 *p = p_protect_info; + + /* Content protection info - support SCMS-T */ + *p_num_protect = 1; + *p++ = BTA_AV_CP_LOSC; + UINT16_TO_STREAM(p, BTA_AV_CP_SCMS_T_ID); + + } +#endif + /* Set up for SBC codec for SRC*/ + *p_codec_type = BTA_AV_CODEC_SBC; + + /* This should not fail because we are using constants for parameters */ + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_caps, p_codec_info); + + /* Codec is valid */ + return TRUE; +#if (BTA_AV_SINK_INCLUDED == TRUE) + case BTC_SV_AV_AA_SBC_SINK_INDEX: + *p_codec_type = BTA_AV_CODEC_SBC; + + /* This should not fail because we are using constants for parameters */ + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_sink_caps, p_codec_info); + + /* Codec is valid */ + return TRUE; +#endif + default: + /* Not valid */ + return FALSE; + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_disc_res + ** + ** Description This callout function is executed by AV to report the + ** number of stream end points (SEP) were found during the + ** AVDT stream discovery process. + ** + ** + ** Returns void. + ** + *******************************************************************************/ +void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk, + UINT8 num_src, BD_ADDR addr, UINT16 uuid_local) +{ + tBTA_AV_CO_PEER *p_peer; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d num_src:%d", + hndl, num_seps, num_snk, num_src); + + /* Find the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) { + APPL_TRACE_ERROR("bta_av_co_audio_disc_res could not find peer entry"); + return; + } + + /* Sanity check : this should never happen */ + if (p_peer->opened) { + APPL_TRACE_ERROR("bta_av_co_audio_disc_res peer already opened"); + } + + /* Copy the discovery results */ + bdcpy(p_peer->addr, addr); + p_peer->num_snks = num_snk; + p_peer->num_srcs = num_src; + p_peer->num_seps = num_seps; + p_peer->num_rx_snks = 0; + p_peer->num_rx_srcs = 0; + p_peer->num_sup_snks = 0; + if (uuid_local == UUID_SERVCLASS_AUDIO_SINK) { + p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE; + } else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE) { + p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SINK; + } +} + +/******************************************************************************* + ** + ** Function bta_av_build_src_cfg + ** + ** Description This function will build preferred config from src capabilities + ** + ** + ** Returns Pass or Fail for current getconfig. + ** + *******************************************************************************/ +void bta_av_build_src_cfg (UINT8 *p_pref_cfg, UINT8 *p_src_cap) +{ + tA2D_SBC_CIE src_cap; + tA2D_SBC_CIE pref_cap; + UINT8 status = 0; + + /* initialize it to default SBC configuration */ + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &btc_av_sbc_default_config, p_pref_cfg); + /* now try to build a preferred one */ + /* parse configuration */ + if ((status = A2D_ParsSbcInfo(&src_cap, p_src_cap, TRUE)) != 0) { + APPL_TRACE_DEBUG(" Cant parse src cap ret = %d", status); + return ; + } + + if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_48) { + pref_cap.samp_freq = A2D_SBC_IE_SAMP_FREQ_48; + } else if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_44) { + pref_cap.samp_freq = A2D_SBC_IE_SAMP_FREQ_44; + } + + if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_JOINT) { + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_JOINT; + } else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_STEREO) { + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_STEREO; + } else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_DUAL) { + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_DUAL; + } else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_MONO) { + pref_cap.ch_mode = A2D_SBC_IE_CH_MD_MONO; + } + + if (src_cap.block_len & A2D_SBC_IE_BLOCKS_16) { + pref_cap.block_len = A2D_SBC_IE_BLOCKS_16; + } else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_12) { + pref_cap.block_len = A2D_SBC_IE_BLOCKS_12; + } else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_8) { + pref_cap.block_len = A2D_SBC_IE_BLOCKS_8; + } else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_4) { + pref_cap.block_len = A2D_SBC_IE_BLOCKS_4; + } + + if (src_cap.num_subbands & A2D_SBC_IE_SUBBAND_8) { + pref_cap.num_subbands = A2D_SBC_IE_SUBBAND_8; + } else if (src_cap.num_subbands & A2D_SBC_IE_SUBBAND_4) { + pref_cap.num_subbands = A2D_SBC_IE_SUBBAND_4; + } + + if (src_cap.alloc_mthd & A2D_SBC_IE_ALLOC_MD_L) { + pref_cap.alloc_mthd = A2D_SBC_IE_ALLOC_MD_L; + } else if (src_cap.alloc_mthd & A2D_SBC_IE_ALLOC_MD_S) { + pref_cap.alloc_mthd = A2D_SBC_IE_ALLOC_MD_S; + } + + pref_cap.max_bitpool = src_cap.max_bitpool; + pref_cap.min_bitpool = src_cap.min_bitpool; + + A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &pref_cap, p_pref_cfg); +} + +/******************************************************************************* + ** + ** Function bta_av_audio_sink_getconfig + ** + ** Description This callout function is executed by AV to retrieve the + ** desired codec and content protection configuration for the + ** A2DP Sink audio stream in Initiator. + ** + ** + ** Returns Pass or Fail for current getconfig. + ** + *******************************************************************************/ +UINT8 bta_av_audio_sink_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect, + UINT8 *p_protect_info) +{ + + UINT8 result = A2D_FAIL; + BOOLEAN supported; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_src; + UINT8 pref_cfg[AVDT_CODEC_SIZE]; + UINT8 index; + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig handle:0x%x codec_type:%d seid:%d", + hndl, codec_type, seid); + APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x", + *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) { + APPL_TRACE_ERROR("bta_av_audio_sink_getconfig could not find peer entry"); + return A2D_FAIL; + } + + APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", + p_peer->opened, p_peer->num_srcs, p_peer->num_rx_srcs, p_peer->num_sup_srcs); + + p_peer->num_rx_srcs++; + + /* Check if this is a supported configuration */ + supported = FALSE; + switch (codec_type) { + case BTA_AV_CODEC_SBC: + supported = TRUE; + break; + + default: + break; + } + + if (supported) { + /* If there is room for a new one */ + if (p_peer->num_sup_srcs < BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs)) { + p_src = &p_peer->srcs[p_peer->num_sup_srcs++]; + + APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig saved caps[%x:%x:%x:%x:%x:%x]", + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); + + memcpy(p_src->codec_caps, p_codec_info, AVDT_CODEC_SIZE); + p_src->codec_type = codec_type; + p_src->sep_info_idx = *p_sep_info_idx; + p_src->seid = seid; + p_src->num_protect = *p_num_protect; + memcpy(p_src->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN); + } else { + APPL_TRACE_ERROR("bta_av_audio_sink_getconfig no more room for SRC info"); + } + } + + /* If last SNK get capabilities or all supported codec caps retrieved */ + if ((p_peer->num_rx_srcs == p_peer->num_srcs) || + (p_peer->num_sup_srcs == BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs))) { + APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig last SRC reached"); + + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_disable(); + + /* Find a src that matches the codec config */ + if (bta_av_co_audio_peer_src_supports_codec(p_peer, &index)) { + APPL_TRACE_DEBUG(" Codec Supported "); + p_src = &p_peer->srcs[index]; + + /* Build the codec configuration for this sink */ + { + /* Save the new configuration */ + p_peer->p_src = p_src; + /* get preferred config from src_caps */ + bta_av_build_src_cfg(pref_cfg, p_src->codec_caps); + memcpy(p_peer->codec_cfg, pref_cfg, AVDT_CODEC_SIZE); + + APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig p_codec_info[%x:%x:%x:%x:%x:%x]", + p_peer->codec_cfg[1], p_peer->codec_cfg[2], p_peer->codec_cfg[3], + p_peer->codec_cfg[4], p_peer->codec_cfg[5], p_peer->codec_cfg[6]); + /* By default, no content protection */ + *p_num_protect = 0; + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + p_peer->cp_active = FALSE; + bta_av_co_cb.cp.active = FALSE; +#endif + + *p_sep_info_idx = p_src->sep_info_idx; + memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE); + result = A2D_SUCCESS; + } + } + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_enable(); + } + return result; +} +/******************************************************************************* + ** + ** Function bta_av_co_audio_getconfig + ** + ** Description This callout function is executed by AV to retrieve the + ** desired codec and content protection configuration for the + ** audio stream. + ** + ** + ** Returns Stream codec and content protection configuration info. + ** + *******************************************************************************/ +UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect, + UINT8 *p_protect_info) + +{ + UINT8 result = A2D_FAIL; + BOOLEAN supported; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + UINT8 codec_cfg[AVDT_CODEC_SIZE]; + UINT8 index; + + FUNC_TRACE(); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) { + APPL_TRACE_ERROR("bta_av_co_audio_getconfig could not find peer entry"); + return A2D_FAIL; + } + + if (p_peer->uuid_to_connect == UUID_SERVCLASS_AUDIO_SOURCE) { + result = bta_av_audio_sink_getconfig(hndl, codec_type, p_codec_info, p_sep_info_idx, + seid, p_num_protect, p_protect_info); + return result; + } + APPL_TRACE_DEBUG("bta_av_co_audio_getconfig handle:0x%x codec_type:%d seid:%d", + hndl, codec_type, seid); + APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x", + *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); + + APPL_TRACE_DEBUG("bta_av_co_audio_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", + p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks); + + p_peer->num_rx_snks++; + + /* Check if this is a supported configuration */ + supported = FALSE; + switch (codec_type) { + case BTA_AV_CODEC_SBC: + supported = TRUE; + break; + + default: + break; + } + + if (supported) { + /* If there is room for a new one */ + if (p_peer->num_sup_snks < BTA_AV_CO_NUM_ELEMENTS(p_peer->snks)) { + p_sink = &p_peer->snks[p_peer->num_sup_snks++]; + + APPL_TRACE_DEBUG("bta_av_co_audio_getconfig saved caps[%x:%x:%x:%x:%x:%x]", + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); + + memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE); + p_sink->codec_type = codec_type; + p_sink->sep_info_idx = *p_sep_info_idx; + p_sink->seid = seid; + p_sink->num_protect = *p_num_protect; + memcpy(p_sink->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN); + } else { + APPL_TRACE_ERROR("bta_av_co_audio_getconfig no more room for SNK info"); + } + } + + /* If last SNK get capabilities or all supported codec capa retrieved */ + if ((p_peer->num_rx_snks == p_peer->num_snks) || + (p_peer->num_sup_snks == BTA_AV_CO_NUM_ELEMENTS(p_peer->snks))) { + APPL_TRACE_DEBUG("bta_av_co_audio_getconfig last sink reached"); + + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_disable(); + + /* Find a sink that matches the codec config */ + if (bta_av_co_audio_peer_supports_codec(p_peer, &index)) { + /* stop fetching caps once we retrieved a supported codec */ + if (p_peer->acp) { + *p_sep_info_idx = p_peer->num_seps; + APPL_TRACE_EVENT("no need to fetch more SEPs"); + } + + p_sink = &p_peer->snks[index]; + + /* Build the codec configuration for this sink */ + if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) { + APPL_TRACE_DEBUG("bta_av_co_audio_getconfig reconfig p_codec_info[%x:%x:%x:%x:%x:%x]", + codec_cfg[1], codec_cfg[2], codec_cfg[3], + codec_cfg[4], codec_cfg[5], codec_cfg[6]); + + /* Save the new configuration */ + p_peer->p_snk = p_sink; + memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE); + + /* By default, no content protection */ + *p_num_protect = 0; + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + /* Check if this sink supports SCMS */ + if (bta_av_co_audio_sink_has_scmst(p_sink)) { + p_peer->cp_active = TRUE; + bta_av_co_cb.cp.active = TRUE; + *p_num_protect = BTA_AV_CP_INFO_LEN; + memcpy(p_protect_info, bta_av_co_cp_scmst, BTA_AV_CP_INFO_LEN); + } else { + p_peer->cp_active = FALSE; + bta_av_co_cb.cp.active = FALSE; + } +#endif + + /* If acceptor -> reconfig otherwise reply for configuration */ + if (p_peer->acp) { + if (p_peer->recfg_needed) { + APPL_TRACE_DEBUG("bta_av_co_audio_getconfig call BTA_AvReconfig(x%x)", hndl); + BTA_AvReconfig(hndl, TRUE, p_sink->sep_info_idx, p_peer->codec_cfg, *p_num_protect, (UINT8 *)bta_av_co_cp_scmst); + } + } else { + *p_sep_info_idx = p_sink->sep_info_idx; + memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE); + } + result = A2D_SUCCESS; + } + } + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_enable(); + } + return result; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_setconfig + ** + ** Description This callout function is executed by AV to set the codec and + ** content protection configuration of the audio stream. + ** + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, UINT8 num_protect, UINT8 *p_protect_info, + UINT8 t_local_sep, UINT8 avdt_handle) +{ + tBTA_AV_CO_PEER *p_peer; + UINT8 status = A2D_SUCCESS; + UINT8 category = A2D_SUCCESS; + BOOLEAN recfg_needed = FALSE; + BOOLEAN codec_cfg_supported = FALSE; + UNUSED(seid); + UNUSED(addr); + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_setconfig p_codec_info[%x:%x:%x:%x:%x:%x]", + p_codec_info[1], p_codec_info[2], p_codec_info[3], + p_codec_info[4], p_codec_info[5], p_codec_info[6]); + APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x", + num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) { + APPL_TRACE_ERROR("bta_av_co_audio_setconfig could not find peer entry"); + + /* Call call-in rejecting the configuration */ + bta_av_ci_setconfig(hndl, A2D_BUSY, AVDT_ASC_CODEC, 0, NULL, FALSE, avdt_handle); + return; + } + APPL_TRACE_DEBUG("bta_av_co_audio_setconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", + p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks); + + /* Sanity check: should not be opened at this point */ + if (p_peer->opened) { + APPL_TRACE_ERROR("bta_av_co_audio_setconfig peer already in use"); + } + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + if (num_protect != 0) { + /* If CP is supported */ + if ((num_protect != 1) || + (bta_av_co_cp_is_scmst(p_protect_info) == FALSE)) { + APPL_TRACE_ERROR("bta_av_co_audio_setconfig wrong CP configuration"); + status = A2D_BAD_CP_TYPE; + category = AVDT_ASC_PROTECT; + } + } +#else + /* Do not support content protection for the time being */ + if (num_protect != 0) { + APPL_TRACE_ERROR("bta_av_co_audio_setconfig wrong CP configuration"); + status = A2D_BAD_CP_TYPE; + category = AVDT_ASC_PROTECT; + } +#endif + if (status == A2D_SUCCESS) { + if (AVDT_TSEP_SNK == t_local_sep) { + codec_cfg_supported = bta_av_co_audio_sink_supports_config(codec_type, p_codec_info); + APPL_TRACE_DEBUG(" Peer is A2DP SRC "); + } + if (AVDT_TSEP_SRC == t_local_sep) { + codec_cfg_supported = bta_av_co_audio_media_supports_config(codec_type, p_codec_info); + APPL_TRACE_DEBUG(" Peer is A2DP SINK "); + } + /* Check if codec configuration is supported */ + if (codec_cfg_supported) { + + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_disable(); + + /* Check if the configuration matches the current codec config */ + switch (bta_av_co_cb.codec_cfg.id) { + case BTC_AV_CODEC_SBC: + if ((codec_type != BTA_AV_CODEC_SBC) || memcmp(p_codec_info, bta_av_co_cb.codec_cfg.info, 5)) { + recfg_needed = TRUE; + } else if ((num_protect == 1) && (!bta_av_co_cb.cp.active)) { + recfg_needed = TRUE; + } + + /* if remote side requests a restricted notify sinks preferred bitpool range as all other params are + already checked for validify */ + APPL_TRACE_EVENT("remote peer setconfig bitpool range [%d:%d]", + p_codec_info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] ); + + bta_av_co_cb.codec_cfg_setconfig.id = BTC_AV_CODEC_SBC; + memcpy(bta_av_co_cb.codec_cfg_setconfig.info, p_codec_info, AVDT_CODEC_SIZE); + if (AVDT_TSEP_SNK == t_local_sep) { + /* If Peer is SRC, and our cfg subset matches with what is requested by peer, then + just accept what peer wants */ + memcpy(bta_av_co_cb.codec_cfg.info, p_codec_info, AVDT_CODEC_SIZE); + recfg_needed = FALSE; + } + break; + + + default: + APPL_TRACE_ERROR("bta_av_co_audio_setconfig unsupported cid %d", bta_av_co_cb.codec_cfg.id); + recfg_needed = TRUE; + break; + } + /* Protect access to bta_av_co_cb.codec_cfg */ + GKI_enable(); + } else { + category = AVDT_ASC_CODEC; + status = A2D_WRONG_CODEC; + } + } + + if (status != A2D_SUCCESS) { + APPL_TRACE_DEBUG("bta_av_co_audio_setconfig reject s=%d c=%d", status, category); + + /* Call call-in rejecting the configuration */ + bta_av_ci_setconfig(hndl, status, category, 0, NULL, FALSE, avdt_handle); + } else { + /* Mark that this is an acceptor peer */ + p_peer->acp = TRUE; + p_peer->recfg_needed = recfg_needed; + + APPL_TRACE_DEBUG("bta_av_co_audio_setconfig accept reconf=%d", recfg_needed); + + /* Call call-in accepting the configuration */ + bta_av_ci_setconfig(hndl, A2D_SUCCESS, A2D_SUCCESS, 0, NULL, recfg_needed, avdt_handle); + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_open + ** + ** Description This function is called by AV when the audio stream connection + ** is opened. + ** + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_open(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, + UINT16 mtu) +{ + tBTA_AV_CO_PEER *p_peer; + UNUSED(p_codec_info); + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_open mtu:%d codec_type:%d", mtu, codec_type); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) { + APPL_TRACE_ERROR("bta_av_co_audio_setconfig could not find peer entry"); + } else { + p_peer->opened = TRUE; + p_peer->mtu = mtu; + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_close + ** + ** Description This function is called by AV when the audio stream connection + ** is closed. + ** + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu) + +{ + tBTA_AV_CO_PEER *p_peer; + UNUSED(codec_type); + UNUSED(mtu); + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_close"); + + /* Retrieve the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer) { + /* Mark the peer closed and clean the peer info */ + memset(p_peer, 0, sizeof(*p_peer)); + } else { + APPL_TRACE_ERROR("bta_av_co_audio_close could not find peer entry"); + } + + /* reset remote preference through setconfig */ + bta_av_co_cb.codec_cfg_setconfig.id = BTC_AV_CODEC_NONE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_start + ** + ** Description This function is called by AV when the audio streaming data + ** transfer is started. + ** + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, + UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr) +{ + UNUSED(hndl); + UNUSED(codec_type); + UNUSED(p_codec_info); + UNUSED(p_no_rtp_hdr); + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_start"); + +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_stop + ** + ** Description This function is called by AV when the audio streaming data + ** transfer is stopped. + ** + ** + ** Returns void + ** + *******************************************************************************/ +extern void bta_av_co_audio_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type) +{ + UNUSED(hndl); + UNUSED(codec_type); + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_stop"); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_src_data_path + ** + ** Description This function is called to manage data transfer from + ** the audio codec to AVDTP. + ** + ** Returns Pointer to the GKI buffer to send, NULL if no buffer to send + ** + *******************************************************************************/ +void *bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, UINT32 *p_len, + UINT32 *p_timestamp) +{ + BT_HDR *p_buf; + UNUSED(p_len); + + FUNC_TRACE(); + + p_buf = btc_media_aa_readbuf(); + if (p_buf != NULL) { + switch (codec_type) { + case BTA_AV_CODEC_SBC: + /* In media packet SBC, the following information is available: + * p_buf->layer_specific : number of SBC frames in the packet + * p_buf->word[0] : timestamp + */ + /* Retrieve the timestamp information from the media packet */ + *p_timestamp = *((UINT32 *) (p_buf + 1)); + + /* Set up packet header */ + bta_av_sbc_bld_hdr(p_buf, p_buf->layer_specific); + break; + + + default: + APPL_TRACE_ERROR("bta_av_co_audio_src_data_path Unsupported codec type (%d)", codec_type); + break; + } +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + { + UINT8 *p; + if (bta_av_co_cp_is_active()) { + p_buf->len++; + p_buf->offset--; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + *p = bta_av_co_cp_get_flag(); + } + } +#endif + } + return p_buf; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_drop + ** + ** Description An Audio packet is dropped. . + ** It's very likely that the connected headset with this handle + ** is moved far away. The implementation may want to reduce + ** the encoder bit rate setting to reduce the packet size. + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_drop(tBTA_AV_HNDL hndl) +{ + FUNC_TRACE(); + + APPL_TRACE_ERROR("bta_av_co_audio_drop dropped: x%x", hndl); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_delay + ** + ** Description This function is called by AV when the audio stream connection + ** needs to send the initial delay report to the connected SRC. + ** + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, UINT16 delay) +{ + FUNC_TRACE(); + + APPL_TRACE_ERROR("bta_av_co_audio_delay handle: x%x, delay:0x%x", hndl, delay); +} + + + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_build_config + ** + ** Description Build the codec configuration + ** + ** Returns TRUE if the codec was built successfully, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + memset(p_codec_cfg, 0, AVDT_CODEC_SIZE); + + switch (bta_av_co_cb.codec_cfg.id) { + case BTC_AV_CODEC_SBC: + /* only copy the relevant portions for this codec to avoid issues when + comparing codec configs covering larger codec sets than SBC (7 bytes) */ + memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg.info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF + 1); + + /* Update the bit pool boundaries with the codec capabilities */ + p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]; + p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]; + + APPL_TRACE_EVENT("bta_av_co_audio_codec_build_config : bitpool min %d, max %d", + p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); + break; + default: + APPL_TRACE_ERROR("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg.id); + return FALSE; + break; + } + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_cfg_matches_caps + ** + ** Description Check if a codec config matches a codec capabilities + ** + ** Returns TRUE if it codec config is supported, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_codec_cfg_matches_caps(UINT8 codec_id, const UINT8 *p_codec_caps, const UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + switch (codec_id) { + case BTC_AV_CODEC_SBC: + + APPL_TRACE_EVENT("bta_av_co_audio_codec_cfg_matches_caps : min %d/%d max %d/%d", + p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], + p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); + + /* Must match all items exactly except bitpool boundaries which can be adjusted */ + if (!((p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF] & p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF]) && + (p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF] & p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]))) { + APPL_TRACE_EVENT("FALSE %x %x %x %x", + p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF], + p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF], + p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF], + p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]); + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR("bta_av_co_audio_codec_cfg_matches_caps: unsupported codec id %d", codec_id); + return FALSE; + break; + } + APPL_TRACE_EVENT("TRUE"); + + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_match + ** + ** Description Check if a codec capabilities supports the codec config + ** + ** Returns TRUE if the connection supports this codec, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_codec_match(const UINT8 *p_codec_caps) +{ + FUNC_TRACE(); + + return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg.id, p_codec_caps, bta_av_co_cb.codec_cfg.info); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_peer_reset_config + ** + ** Description Reset the peer codec configuration + ** + ** Returns Nothing + ** + *******************************************************************************/ +static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer) +{ + FUNC_TRACE(); + + /* Indicate that there is no currently selected sink */ + p_peer->p_snk = NULL; +} + +/******************************************************************************* + ** + ** Function bta_av_co_cp_is_scmst + ** + ** Description Check if a content protection service is SCMS-T + ** + ** Returns TRUE if this CP is SCMS-T, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo) +{ + UINT16 cp_id; + FUNC_TRACE(); + + if (*p_protectinfo >= BTA_AV_CP_LOSC) { + p_protectinfo++; + STREAM_TO_UINT16(cp_id, p_protectinfo); + if (cp_id == BTA_AV_CP_SCMS_T_ID) { + APPL_TRACE_DEBUG("bta_av_co_cp_is_scmst: SCMS-T found"); + return TRUE; + } + } + + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_sink_has_scmst + ** + ** Description Check if a sink supports SCMS-T + ** + ** Returns TRUE if the sink supports this CP, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink) +{ + UINT8 index; + const UINT8 *p; + FUNC_TRACE(); + + /* Check if sink supports SCMS-T */ + index = p_sink->num_protect; + p = &p_sink->protect_info[0]; + + while (index) { + if (bta_av_co_cp_is_scmst(p)) { + return TRUE; + } + /* Move to the next SC */ + p += *p + 1; + /* Decrement the SC counter */ + index--; + } + APPL_TRACE_DEBUG("bta_av_co_audio_sink_has_scmst: SCMS-T not found"); + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_sink_supports_cp + ** + ** Description Check if a sink supports the current content protection + ** + ** Returns TRUE if the sink supports this CP, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK *p_sink) +{ + FUNC_TRACE(); + + /* Check if content protection is enabled for this stream */ + if (bta_av_co_cp_get_flag() != BTA_AV_CP_SCMS_COPY_FREE) { + return bta_av_co_audio_sink_has_scmst(p_sink); + } else { + APPL_TRACE_DEBUG("bta_av_co_audio_sink_supports_cp: not required"); + return TRUE; + } +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_peer_supports_codec + ** + ** Description Check if a connection supports the codec config + ** + ** Returns TRUE if the connection supports this codec, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index) +{ + int index; + UINT8 codec_type; + FUNC_TRACE(); + + /* Configure the codec type to look for */ + codec_type = bta_av_co_cb.codec_cfg.id; + + + for (index = 0; index < p_peer->num_sup_snks; index++) { + if (p_peer->snks[index].codec_type == codec_type) { + switch (bta_av_co_cb.codec_cfg.id) { + case BTC_AV_CODEC_SBC: + if (p_snk_index) { + *p_snk_index = index; + } + return bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps); + break; + + + default: + APPL_TRACE_ERROR("bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg.id); + return FALSE; + break; + } + } + } + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_peer_src_supports_codec + ** + ** Description Check if a peer acting as src supports codec config + ** + ** Returns TRUE if the connection supports this codec, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index) +{ + int index; + UINT8 codec_type; + FUNC_TRACE(); + + /* Configure the codec type to look for */ + codec_type = bta_av_co_cb.codec_cfg.id; + + + for (index = 0; index < p_peer->num_sup_srcs; index++) { + if (p_peer->srcs[index].codec_type == codec_type) { + switch (bta_av_co_cb.codec_cfg.id) { + case BTC_AV_CODEC_SBC: + if (p_src_index) { + *p_src_index = index; + } + if (0 == bta_av_sbc_cfg_matches_cap((UINT8 *)p_peer->srcs[index].codec_caps, + (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) { + return TRUE; + } + break; + + default: + APPL_TRACE_ERROR("peer_src_supports_codec: unsupported codec id %d", + bta_av_co_cb.codec_cfg.id); + return FALSE; + break; + } + } + } + return FALSE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_sink_supports_config + ** + ** Description Check if the media source supports a given configuration + ** + ** Returns TRUE if the media source supports this config, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + switch (codec_type) { + case BTA_AV_CODEC_SBC: + if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) { + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type); + return FALSE; + break; + } + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_media_supports_config + ** + ** Description Check if the media sink supports a given configuration + ** + ** Returns TRUE if the media source supports this config, FALSE otherwise + ** + *******************************************************************************/ +static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) +{ + FUNC_TRACE(); + + switch (codec_type) { + case BTA_AV_CODEC_SBC: + if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps)) { + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type); + return FALSE; + break; + } + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_supported + ** + ** Description Check if all opened connections are compatible with a codec + ** configuration and content protection + ** + ** Returns TRUE if all opened devices support this codec, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_codec_supported(tBTC_STATUS *p_status) +{ + UINT8 index; + UINT8 snk_index; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + UINT8 codec_cfg[AVDT_CODEC_SIZE]; + UINT8 num_protect = 0; +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + BOOLEAN cp_active; +#endif + + FUNC_TRACE(); + + APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported"); + + /* Check AV feeding is supported */ + *p_status = BTC_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED; + + for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) { + p_peer = &bta_av_co_cb.peers[index]; + if (p_peer->opened) { + if (bta_av_co_audio_peer_supports_codec(p_peer, &snk_index)) { + p_sink = &p_peer->snks[snk_index]; + + /* Check that this sink is compatible with the CP */ + if (!bta_av_co_audio_sink_supports_cp(p_sink)) { + APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported sink %d of peer %d doesn't support cp", + snk_index, index); + *p_status = BTC_ERROR_SRV_AV_CP_NOT_SUPPORTED; + return FALSE; + } + + /* Build the codec configuration for this sink */ + if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) { +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + /* Check if this sink supports SCMS */ + cp_active = bta_av_co_audio_sink_has_scmst(p_sink); +#endif + /* Check if this is a new configuration (new sink or new config) */ + if ((p_sink != p_peer->p_snk) || + (memcmp(codec_cfg, p_peer->codec_cfg, AVDT_CODEC_SIZE)) +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + || (p_peer->cp_active != cp_active) +#endif + ) { + /* Save the new configuration */ + p_peer->p_snk = p_sink; + memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE); +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + p_peer->cp_active = cp_active; + if (p_peer->cp_active) { + bta_av_co_cb.cp.active = TRUE; + num_protect = BTA_AV_CP_INFO_LEN; + } else { + bta_av_co_cb.cp.active = FALSE; + } +#endif + APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported call BTA_AvReconfig(x%x)", BTA_AV_CO_AUDIO_INDX_TO_HNDL(index)); + BTA_AvReconfig(BTA_AV_CO_AUDIO_INDX_TO_HNDL(index), TRUE, p_sink->sep_info_idx, + p_peer->codec_cfg, num_protect, (UINT8 *)bta_av_co_cp_scmst); + } + } + } else { + APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported index %d doesn't support codec", index); + return FALSE; + } + } + } + + *p_status = BTC_SUCCESS; + return TRUE; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_reset + ** + ** Description Reset the current codec configuration + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_codec_reset(void) +{ + GKI_disable(); + FUNC_TRACE(); + + /* Reset the current configuration to SBC */ + bta_av_co_cb.codec_cfg.id = BTC_AV_CODEC_SBC; + + if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btc_av_sbc_default_config, bta_av_co_cb.codec_cfg.info) != A2D_SUCCESS) { + APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed"); + } + + GKI_enable(); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_set_codec + ** + ** Description Set the current codec configuration from the feeding type. + ** This function is starting to modify the configuration, it + ** should be protected. + ** + ** Returns TRUE if successful, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_set_codec(const tBTC_AV_MEDIA_FEEDINGS *p_feeding, tBTC_STATUS *p_status) +{ + tA2D_SBC_CIE sbc_config; + tBTC_AV_CODEC_INFO new_cfg; + + FUNC_TRACE(); + + /* Check AV feeding is supported */ + *p_status = BTC_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED; + + APPL_TRACE_DEBUG("bta_av_co_audio_set_codec cid=%d", p_feeding->format); + + /* Supported codecs */ + switch (p_feeding->format) { + case BTC_AV_CODEC_PCM: + new_cfg.id = BTC_AV_CODEC_SBC; + + sbc_config = btc_av_sbc_default_config; + if ((p_feeding->cfg.pcm.num_channel != 1) && + (p_feeding->cfg.pcm.num_channel != 2)) { + APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM channel number unsupported"); + return FALSE; + } + if ((p_feeding->cfg.pcm.bit_per_sample != 8) && + (p_feeding->cfg.pcm.bit_per_sample != 16)) { + APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM sample size unsupported"); + return FALSE; + } + switch (p_feeding->cfg.pcm.sampling_freq) { + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 48000: + sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_48; + break; + + case 11025: + case 22050: + case 44100: + sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_44; + break; + default: + APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM sampling frequency unsupported"); + return FALSE; + break; + } + /* Build the codec config */ + if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &sbc_config, new_cfg.info) != A2D_SUCCESS) { + APPL_TRACE_ERROR("bta_av_co_audio_set_codec A2D_BldSbcInfo failed"); + return FALSE; + } + break; + + + default: + APPL_TRACE_ERROR("bta_av_co_audio_set_codec Feeding format unsupported"); + return FALSE; + break; + } + + /* The new config was correctly built */ + bta_av_co_cb.codec_cfg = new_cfg; + + + /* Check all devices support it */ + *p_status = BTC_SUCCESS; + return bta_av_co_audio_codec_supported(p_status); +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_get_sbc_config + ** + ** Description Retrieves the SBC codec configuration. If the codec in use + ** is not SBC, return the default SBC codec configuration. + ** + ** Returns TRUE if codec is SBC, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu) +{ + BOOLEAN result = FALSE; + UINT8 index, jndex; + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + + APPL_TRACE_EVENT("bta_av_co_cb.codec_cfg.id : codec 0x%x", bta_av_co_cb.codec_cfg.id); + + /* Minimum MTU is by default very large */ + *p_minmtu = 0xFFFF; + + GKI_disable(); + if (bta_av_co_cb.codec_cfg.id == BTC_AV_CODEC_SBC) { + if (A2D_ParsSbcInfo(p_sbc_config, bta_av_co_cb.codec_cfg.info, FALSE) == A2D_SUCCESS) { + for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) { + p_peer = &bta_av_co_cb.peers[index]; + if (p_peer->opened) { + if (p_peer->mtu < *p_minmtu) { + *p_minmtu = p_peer->mtu; + } + for (jndex = 0; jndex < p_peer->num_sup_snks; jndex++) { + p_sink = &p_peer->snks[jndex]; + if (p_sink->codec_type == A2D_MEDIA_CT_SBC) { + /* Update the bitpool boundaries of the current config */ + p_sbc_config->min_bitpool = + BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], + p_sbc_config->min_bitpool); + p_sbc_config->max_bitpool = + BTA_AV_CO_MIN(p_sink->codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], + p_sbc_config->max_bitpool); + APPL_TRACE_EVENT("bta_av_co_audio_get_sbc_config : sink bitpool min %d, max %d", + p_sbc_config->min_bitpool, p_sbc_config->max_bitpool); + break; + } + } + } + } + result = TRUE; + } + } + + if (!result) { + /* Not SBC, still return the default values */ + *p_sbc_config = btc_av_sbc_default_config; + } + GKI_enable(); + + return result; +} + +/******************************************************************************* + ** + ** Function bta_av_co_audio_discard_config + ** + ** Description Discard the codec configuration of a connection + ** + ** Returns Nothing + ** + *******************************************************************************/ +void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl) +{ + tBTA_AV_CO_PEER *p_peer; + + FUNC_TRACE(); + + /* Find the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) { + APPL_TRACE_ERROR("bta_av_co_audio_discard_config could not find peer entry"); + return; + } + + /* Reset the peer codec configuration */ + bta_av_co_audio_peer_reset_config(p_peer); +} + +/******************************************************************************* + ** + ** Function bta_av_co_init + ** + ** Description Initialization + ** + ** Returns Nothing + ** + *******************************************************************************/ +void bta_av_co_init(void) +{ + FUNC_TRACE(); + + /* Reset the control block */ + memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb)); + + bta_av_co_cb.codec_cfg_setconfig.id = BTC_AV_CODEC_NONE; + +#if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) + bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_NEVER); +#else + bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_FREE); +#endif + + /* Reset the current config */ + bta_av_co_audio_codec_reset(); +} + + +/******************************************************************************* + ** + ** Function bta_av_co_peer_cp_supported + ** + ** Description Checks if the peer supports CP + ** + ** Returns TRUE if the peer supports CP + ** + *******************************************************************************/ +BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl) +{ + tBTA_AV_CO_PEER *p_peer; + tBTA_AV_CO_SINK *p_sink; + UINT8 index; + + FUNC_TRACE(); + + /* Find the peer info */ + p_peer = bta_av_co_get_peer(hndl); + if (p_peer == NULL) { + APPL_TRACE_ERROR("bta_av_co_peer_cp_supported could not find peer entry"); + return FALSE; + } + + for (index = 0; index < p_peer->num_sup_snks; index++) { + p_sink = &p_peer->snks[index]; + if (p_sink->codec_type == A2D_MEDIA_CT_SBC) { + return bta_av_co_audio_sink_has_scmst(p_sink); + } + } + APPL_TRACE_ERROR("bta_av_co_peer_cp_supported did not find SBC sink"); + return FALSE; +} + + +/******************************************************************************* + ** + ** Function bta_av_co_get_remote_bitpool_pref + ** + ** Description Check if remote side did a setconfig within the limits + ** of our exported bitpool range. If set we will set the + ** remote preference. + ** + ** Returns TRUE if config set, FALSE otherwize + ** + *******************************************************************************/ + +BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max) +{ + /* check if remote peer did a set config */ + if (bta_av_co_cb.codec_cfg_setconfig.id == BTC_AV_CODEC_NONE) { + return FALSE; + } + + *min = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]; + *max = bta_av_co_cb.codec_cfg_setconfig.info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]; + + return TRUE; +} + +/* the call out functions for audio stream */ +tBTA_AV_CO_FUNCTS bta_av_a2d_cos = { + bta_av_co_audio_init, + bta_av_co_audio_disc_res, + bta_av_co_audio_getconfig, + bta_av_co_audio_setconfig, + bta_av_co_audio_open, + bta_av_co_audio_close, + bta_av_co_audio_start, + bta_av_co_audio_stop, + bta_av_co_audio_src_data_path, + bta_av_co_audio_delay +}; + +#endif /* #if BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_avk.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_avk.c new file mode 100644 index 0000000000..966f8d6ff3 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_avk.c @@ -0,0 +1,1247 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + +/***************************************************************************** + * + * Filename: btc_avk.c + * + * Description: AV implementation + * + *****************************************************************************/ +#include "bt_target.h" +#include +#include "bt_trace.h" +#include "bt_defs.h" +#include "esp_bt_defs.h" +#include "esp_a2dp_api.h" +#include "allocator.h" +#include "btc_dm.h" +#include "btc_av.h" +#include "btc_avrc.h" +#include "btc_util.h" +#include "btc_profile_queue.h" +#include "bta_api.h" +#include "btc_media.h" +#include "bta_av_api.h" +#include "gki.h" +#include "btu.h" +#include "bt_utils.h" +#include "btc_common.h" +#include "btc_manage.h" + +#if BTC_AV_INCLUDED + +/***************************************************************************** +** Constants & Macros +******************************************************************************/ +#define BTC_AV_SERVICE_NAME "Advanced Audio" + +#define BTC_TIMEOUT_AV_OPEN_ON_RC_SECS 2 + +typedef enum { + BTC_AV_STATE_IDLE = 0x0, + BTC_AV_STATE_OPENING, + BTC_AV_STATE_OPENED, + BTC_AV_STATE_STARTED, + BTC_AV_STATE_CLOSING +} btc_av_state_t; + +/* Should not need dedicated suspend state as actual actions are no + different than open state. Suspend flags are needed however to prevent + media task from trying to restart stream during remote suspend or while + we are in the process of a local suspend */ + +#define BTC_AV_FLAG_LOCAL_SUSPEND_PENDING 0x1 +#define BTC_AV_FLAG_REMOTE_SUSPEND 0x2 +#define BTC_AV_FLAG_PENDING_START 0x4 +#define BTC_AV_FLAG_PENDING_STOP 0x8 + +/***************************************************************************** +** Local type definitions +******************************************************************************/ + +typedef struct { + tBTA_AV_HNDL bta_handle; + bt_bdaddr_t peer_bda; + btc_sm_handle_t sm_handle; + UINT8 flags; + tBTA_AV_EDR edr; + UINT8 peer_sep; /* sep type of peer device */ +} btc_av_cb_t; + +typedef struct { + bt_bdaddr_t *target_bda; + uint16_t uuid; +} btc_av_connect_req_t; + +/***************************************************************************** +** Static variables +******************************************************************************/ +static btc_av_cb_t btc_av_cb = {0}; +static TIMER_LIST_ENT tle_av_open_on_rc; + +/* both interface and media task needs to be ready to alloc incoming request */ +#define CHECK_BTAV_INIT() do \ +{ \ + assert (btc_av_cb.sm_handle != NULL); \ +} while (0) + + +/* Helper macro to avoid code duplication in the state machine handlers */ +#define CHECK_RC_EVENT(e, d) \ + case BTA_AV_RC_OPEN_EVT: \ + case BTA_AV_RC_CLOSE_EVT: \ + case BTA_AV_REMOTE_CMD_EVT: \ + case BTA_AV_VENDOR_CMD_EVT: \ + case BTA_AV_META_MSG_EVT: \ + case BTA_AV_RC_FEAT_EVT: \ + case BTA_AV_REMOTE_RSP_EVT: \ + { \ + btc_rc_handler(e, d);\ + }break; \ + +static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *data); +static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *data); +static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *data); +static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *data); +static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *data); + +static const btc_sm_handler_t btc_av_state_handlers[] = { + btc_av_state_idle_handler, + btc_av_state_opening_handler, + btc_av_state_opened_handler, + btc_av_state_started_handler, + btc_av_state_closing_handler +}; + +static void btc_av_event_free_data(btc_sm_event_t event, void *p_data); + +/************************************************************************* +** Extern functions +*************************************************************************/ + +extern tBTA_AV_CO_FUNCTS bta_av_a2d_cos; +/***************************************************************************** +** Local helper functions +******************************************************************************/ +static inline void btc_a2d_cb_to_app(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) +{ + esp_a2d_cb_t btc_a2d_cb = (esp_a2d_cb_t)btc_profile_cb_get(BTC_PID_A2DP); + if (btc_a2d_cb) { + btc_a2d_cb(event, param); + } +} + +UNUSED_ATTR static const char *dump_av_sm_state_name(btc_av_state_t state) +{ + switch (state) { + CASE_RETURN_STR(BTC_AV_STATE_IDLE) + CASE_RETURN_STR(BTC_AV_STATE_OPENING) + CASE_RETURN_STR(BTC_AV_STATE_OPENED) + CASE_RETURN_STR(BTC_AV_STATE_STARTED) + CASE_RETURN_STR(BTC_AV_STATE_CLOSING) + default: return "UNKNOWN_STATE"; + } +} + +UNUSED_ATTR static const char *dump_av_sm_event_name(btc_av_sm_event_t event) +{ + switch ((int)event) { + CASE_RETURN_STR(BTA_AV_ENABLE_EVT) + CASE_RETURN_STR(BTA_AV_REGISTER_EVT) + CASE_RETURN_STR(BTA_AV_OPEN_EVT) + CASE_RETURN_STR(BTA_AV_CLOSE_EVT) + CASE_RETURN_STR(BTA_AV_START_EVT) + CASE_RETURN_STR(BTA_AV_STOP_EVT) + CASE_RETURN_STR(BTA_AV_PROTECT_REQ_EVT) + CASE_RETURN_STR(BTA_AV_PROTECT_RSP_EVT) + CASE_RETURN_STR(BTA_AV_RC_OPEN_EVT) + CASE_RETURN_STR(BTA_AV_RC_CLOSE_EVT) + CASE_RETURN_STR(BTA_AV_REMOTE_CMD_EVT) + CASE_RETURN_STR(BTA_AV_REMOTE_RSP_EVT) + CASE_RETURN_STR(BTA_AV_VENDOR_CMD_EVT) + CASE_RETURN_STR(BTA_AV_VENDOR_RSP_EVT) + CASE_RETURN_STR(BTA_AV_RECONFIG_EVT) + CASE_RETURN_STR(BTA_AV_SUSPEND_EVT) + CASE_RETURN_STR(BTA_AV_PENDING_EVT) + CASE_RETURN_STR(BTA_AV_META_MSG_EVT) + CASE_RETURN_STR(BTA_AV_REJECT_EVT) + CASE_RETURN_STR(BTA_AV_RC_FEAT_EVT) + CASE_RETURN_STR(BTC_SM_ENTER_EVT) + CASE_RETURN_STR(BTC_SM_EXIT_EVT) + CASE_RETURN_STR(BTC_AV_CONNECT_REQ_EVT) + CASE_RETURN_STR(BTC_AV_DISCONNECT_REQ_EVT) + CASE_RETURN_STR(BTC_AV_START_STREAM_REQ_EVT) + CASE_RETURN_STR(BTC_AV_STOP_STREAM_REQ_EVT) + CASE_RETURN_STR(BTC_AV_SUSPEND_STREAM_REQ_EVT) + CASE_RETURN_STR(BTC_AV_SINK_CONFIG_REQ_EVT) + default: return "UNKNOWN_EVENT"; + } +} + +/**************************************************************************** +** Local helper functions +*****************************************************************************/ +/******************************************************************************* +** +** Function btc_initiate_av_open_tmr_hdlr +** +** Description Timer to trigger AV open if the remote headset establishes +** RC connection w/o AV connection. The timer is needed to IOP +** with headsets that do establish AV after RC connection. +** +** Returns void +** +*******************************************************************************/ +static void btc_initiate_av_open_tmr_hdlr(TIMER_LIST_ENT *tle) +{ + BD_ADDR peer_addr; + UNUSED(tle); + btc_av_connect_req_t connect_req; + UNUSED(tle); + /* is there at least one RC connection - There should be */ + if (btc_rc_get_connected_peer(peer_addr)) { + LOG_DEBUG("%s Issuing connect to the remote RC peer", __FUNCTION__); + /* In case of AVRCP connection request, we will initiate SRC connection */ + connect_req.target_bda = (bt_bdaddr_t *)&peer_addr; + connect_req.uuid = UUID_SERVCLASS_AUDIO_SOURCE; + btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_CONNECT_REQ_EVT, (char *)&connect_req); + } else { + LOG_ERROR("%s No connected RC peers", __FUNCTION__); + } +} + +/***************************************************************************** +** Static functions +******************************************************************************/ +static void btc_report_connection_state(esp_a2d_connection_state_t state, bt_bdaddr_t *bd_addr, int disc_rsn) +{ + esp_a2d_cb_param_t param; + memset(¶m, 0, sizeof(esp_a2d_cb_param_t)); + + param.conn_stat.state = state; + if (bd_addr) { + memcpy(param.conn_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t)); + } + if (state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) { + param.conn_stat.disc_rsn = (disc_rsn == 0) ? ESP_A2D_DISC_RSN_NORMAL : + ESP_A2D_DISC_RSN_ABNORMAL; + } + btc_a2d_cb_to_app(ESP_A2D_CONNECTION_STATE_EVT, ¶m); +} + +static void btc_report_audio_state(esp_a2d_audio_state_t state, bt_bdaddr_t *bd_addr) +{ + esp_a2d_cb_param_t param; + memset(¶m, 0, sizeof(esp_a2d_cb_param_t)); + + param.audio_stat.state = state; + if (bd_addr) { + memcpy(param.audio_stat.remote_bda, bd_addr, sizeof(esp_bd_addr_t)); + } + btc_a2d_cb_to_app(ESP_A2D_AUDIO_STATE_EVT, ¶m); +} + +/***************************************************************************** +** +** Function btc_av_state_idle_handler +** +** Description State managing disconnected AV link +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + +static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data) +{ + LOG_DEBUG("%s event:%s flags %x\n", __FUNCTION__, + dump_av_sm_event_name(event), btc_av_cb.flags); + + switch (event) { + case BTC_SM_ENTER_EVT: + /* clear the peer_bda */ + memset(&btc_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t)); + btc_av_cb.flags = 0; + btc_av_cb.edr = 0; + btc_a2dp_on_idle(); + break; + + case BTC_SM_EXIT_EVT: + break; + + case BTA_AV_ENABLE_EVT: + break; + + case BTA_AV_REGISTER_EVT: + btc_av_cb.bta_handle = ((tBTA_AV *)p_data)->registr.hndl; + break; + + case BTA_AV_PENDING_EVT: + case BTC_AV_CONNECT_REQ_EVT: { + if (event == BTC_AV_CONNECT_REQ_EVT) { + memcpy(&btc_av_cb.peer_bda, ((btc_av_connect_req_t *)p_data)->target_bda, + sizeof(bt_bdaddr_t)); + BTA_AvOpen(btc_av_cb.peer_bda.address, btc_av_cb.bta_handle, + TRUE, BTA_SEC_AUTHENTICATE, ((btc_av_connect_req_t *)p_data)->uuid); + } else if (event == BTA_AV_PENDING_EVT) { + bdcpy(btc_av_cb.peer_bda.address, ((tBTA_AV *)p_data)->pend.bd_addr); + BTA_AvOpen(btc_av_cb.peer_bda.address, btc_av_cb.bta_handle, + TRUE, BTA_SEC_AUTHENTICATE, UUID_SERVCLASS_AUDIO_SOURCE); + } + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_OPENING); + } break; + + case BTA_AV_RC_OPEN_EVT: + /* IOP_FIX: Jabra 620 only does RC open without AV open whenever it connects. So + * as per the AV WP, an AVRC connection cannot exist without an AV connection. Therefore, + * we initiate an AV connection if an RC_OPEN_EVT is received when we are in AV_CLOSED state. + * We initiate the AV connection after a small 3s timeout to avoid any collisions from the + * headsets, as some headsets initiate the AVRC connection first and then + * immediately initiate the AV connection + * + * TODO: We may need to do this only on an AVRCP Play. FixMe + */ + + LOG_DEBUG("BTA_AV_RC_OPEN_EVT received w/o AV"); + memset(&tle_av_open_on_rc, 0, sizeof(tle_av_open_on_rc)); + tle_av_open_on_rc.param = (UINT32)btc_initiate_av_open_tmr_hdlr; + btu_start_timer(&tle_av_open_on_rc, BTU_TTYPE_USER_FUNC, + BTC_TIMEOUT_AV_OPEN_ON_RC_SECS); + btc_rc_handler(event, p_data); + break; + + case BTA_AV_REMOTE_CMD_EVT: + case BTA_AV_VENDOR_CMD_EVT: + case BTA_AV_META_MSG_EVT: + case BTA_AV_RC_FEAT_EVT: + case BTA_AV_REMOTE_RSP_EVT: + btc_rc_handler(event, (tBTA_AV *)p_data); + break; + + case BTA_AV_RC_CLOSE_EVT: + if (tle_av_open_on_rc.in_use) { + LOG_DEBUG("BTA_AV_RC_CLOSE_EVT: Stopping AV timer."); + btu_stop_timer(&tle_av_open_on_rc); + } + btc_rc_handler(event, p_data); + break; + + default: + LOG_WARN("%s : unhandled event:%s\n", __FUNCTION__, + dump_av_sm_event_name(event)); + return FALSE; + + } + + return TRUE; +} +/***************************************************************************** +** +** Function btc_av_state_opening_handler +** +** Description Intermediate state managing events during establishment +** of avdtp channel +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + +static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data) +{ + LOG_DEBUG("%s event:%s flags %x\n", __FUNCTION__, + dump_av_sm_event_name(event), btc_av_cb.flags); + + switch (event) { + case BTC_SM_ENTER_EVT: + /* inform the application that we are entering connecting state */ + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_CONNECTING, &(btc_av_cb.peer_bda), 0); + break; + + case BTC_SM_EXIT_EVT: + break; + + case BTA_AV_REJECT_EVT: + LOG_DEBUG(" Received BTA_AV_REJECT_EVT \n"); + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), 0); + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE); + break; + + case BTA_AV_OPEN_EVT: { + tBTA_AV *p_bta_data = (tBTA_AV *)p_data; + esp_a2d_connection_state_t state; + btc_sm_state_t av_state; + LOG_DEBUG("status:%d, edr 0x%x\n", p_bta_data->open.status, + p_bta_data->open.edr); + + if (p_bta_data->open.status == BTA_AV_SUCCESS) { + state = ESP_A2D_CONNECTION_STATE_CONNECTED; + av_state = BTC_AV_STATE_OPENED; + btc_av_cb.edr = p_bta_data->open.edr; + + btc_av_cb.peer_sep = p_bta_data->open.sep; + btc_a2dp_set_peer_sep(p_bta_data->open.sep); + } else { + LOG_WARN("BTA_AV_OPEN_EVT::FAILED status: %d\n", + p_bta_data->open.status ); + state = ESP_A2D_CONNECTION_STATE_DISCONNECTED; + av_state = BTC_AV_STATE_IDLE; + } + + /* inform the application of the event */ + btc_report_connection_state(state, &(btc_av_cb.peer_bda), 0); + /* change state to open/idle based on the status */ + btc_sm_change_state(btc_av_cb.sm_handle, av_state); + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + /* Bring up AVRCP connection too */ + BTA_AvOpenRc(btc_av_cb.bta_handle); + } + btc_queue_advance(); + } break; + + case BTC_AV_SINK_CONFIG_REQ_EVT: { + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + esp_a2d_cb_param_t param; + memcpy(param.audio_cfg.remote_bda, &btc_av_cb.peer_bda, sizeof(esp_bd_addr_t)); + memcpy(¶m.audio_cfg.mcc, p_data, sizeof(esp_a2d_mcc_t)); + btc_a2d_cb_to_app(ESP_A2D_AUDIO_CFG_EVT, ¶m); + } + } break; + + case BTC_AV_CONNECT_REQ_EVT: + // Check for device, if same device which moved to opening then ignore callback + if (memcmp ((bt_bdaddr_t *)p_data, &(btc_av_cb.peer_bda), + sizeof(btc_av_cb.peer_bda)) == 0) { + LOG_DEBUG("%s: Same device moved to Opening state,ignore Connect Req\n", __func__); + btc_queue_advance(); + break; + } else { + LOG_DEBUG("%s: Moved from idle by Incoming Connection request\n", __func__); + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, (bt_bdaddr_t *)p_data, 0); + btc_queue_advance(); + break; + } + + case BTA_AV_PENDING_EVT: + // Check for device, if same device which moved to opening then ignore callback + if (memcmp (((tBTA_AV *)p_data)->pend.bd_addr, &(btc_av_cb.peer_bda), + sizeof(btc_av_cb.peer_bda)) == 0) { + LOG_DEBUG("%s: Same device moved to Opening state,ignore Pending Req\n", __func__); + break; + } else { + LOG_DEBUG("%s: Moved from idle by outgoing Connection request\n", __func__); + BTA_AvDisconnect(((tBTA_AV *)p_data)->pend.bd_addr); + break; + } + + CHECK_RC_EVENT(event, p_data); + + default: + LOG_WARN("%s : unhandled event:%s\n", __FUNCTION__, + dump_av_sm_event_name(event)); + return FALSE; + + } + return TRUE; +} + + +/***************************************************************************** +** +** Function btc_av_state_closing_handler +** +** Description Intermediate state managing events during closing +** of avdtp channel +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + +static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *p_data) +{ + LOG_DEBUG("%s event:%s flags %x\n", __FUNCTION__, + dump_av_sm_event_name(event), btc_av_cb.flags); + + switch (event) { + case BTC_SM_ENTER_EVT: + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + btc_a2dp_set_rx_flush(TRUE); + } + break; + + case BTA_AV_STOP_EVT: + case BTC_AV_STOP_STREAM_REQ_EVT: + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + btc_a2dp_set_rx_flush(TRUE); + } + + btc_a2dp_on_stopped(NULL); + break; + + case BTC_SM_EXIT_EVT: + break; + + case BTA_AV_CLOSE_EVT: { + tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data; + /* inform the application that we are disconnecting */ + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), + close->disc_rsn); + + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE); + break; + } + + /* Handle the RC_CLOSE event for the cleanup */ + case BTA_AV_RC_CLOSE_EVT: + btc_rc_handler(event, (tBTA_AV *)p_data); + break; + + default: + LOG_WARN("%s : unhandled event:%s\n", __FUNCTION__, + dump_av_sm_event_name(event)); + return FALSE; + } + return TRUE; +} + + +/***************************************************************************** +** +** Function btc_av_state_opened_handler +** +** Description Handles AV events while AVDTP is in OPEN state +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + +static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data) +{ + tBTA_AV *p_av = (tBTA_AV *)p_data; + + LOG_DEBUG("%s event:%s flags %x\n", __FUNCTION__, + dump_av_sm_event_name(event), btc_av_cb.flags); + + if ( (event == BTA_AV_REMOTE_CMD_EVT) && (btc_av_cb.flags & BTC_AV_FLAG_REMOTE_SUSPEND) && + (p_av->remote_cmd.rc_id == BTA_AV_RC_PLAY) ) { + LOG_INFO("%s: Resetting remote suspend flag on RC PLAY\n", __FUNCTION__); + btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND; + } + + switch (event) { + case BTC_SM_ENTER_EVT: + btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_STOP; + btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START; + break; + + case BTC_SM_EXIT_EVT: + btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START; + break; + + case BTC_AV_START_STREAM_REQ_EVT: + BTA_AvStart(); + btc_av_cb.flags |= BTC_AV_FLAG_PENDING_START; + break; + + case BTA_AV_START_EVT: { + LOG_INFO("BTA_AV_START_EVT status %d, suspending %d, init %d\n", + p_av->start.status, p_av->start.suspending, p_av->start.initiator); + + if ((p_av->start.status == BTA_SUCCESS) && (p_av->start.suspending == TRUE)) { + return TRUE; + } + + /* remain in open state if status failed */ + if (p_av->start.status != BTA_AV_SUCCESS) { + return FALSE; + } + + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + btc_a2dp_set_rx_flush(FALSE); /* remove flush state, ready for streaming*/ + } + + /* change state to started, send acknowledgement if start is pending */ + if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) { + + /* pending start flag will be cleared when exit current state */ + } + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_STARTED); + + } break; + + case BTC_AV_DISCONNECT_REQ_EVT: + BTA_AvClose(btc_av_cb.bta_handle); + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + BTA_AvCloseRc(btc_av_cb.bta_handle); + } + + /* inform the application that we are disconnecting */ + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0); + break; + + case BTA_AV_CLOSE_EVT: { + /* avdtp link is closed */ + btc_a2dp_on_stopped(NULL); + + tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data; + /* inform the application that we are disconnected */ + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), + close->disc_rsn); + + /* change state to idle, send acknowledgement if start is pending */ + if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) { + /* pending start flag will be cleared when exit current state */ + } + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE); + break; + } + + case BTA_AV_RECONFIG_EVT: + if ((btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) && + (p_av->reconfig.status == BTA_AV_SUCCESS)) { + LOG_WARN("reconfig done BTA_AVstart()\n"); + BTA_AvStart(); + } else if (btc_av_cb.flags & BTC_AV_FLAG_PENDING_START) { + btc_av_cb.flags &= ~BTC_AV_FLAG_PENDING_START; + } + break; + + case BTC_AV_CONNECT_REQ_EVT: + if (memcmp ((bt_bdaddr_t *)p_data, &(btc_av_cb.peer_bda), + sizeof(btc_av_cb.peer_bda)) == 0) { + LOG_DEBUG("%s: Ignore BTC_AVCONNECT_REQ_EVT for same device\n", __func__); + } else { + LOG_DEBUG("%s: Moved to opened by Other Incoming Conn req\n", __func__); + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, + (bt_bdaddr_t *)p_data, ESP_A2D_DISC_RSN_NORMAL); + } + btc_queue_advance(); + break; + + CHECK_RC_EVENT(event, p_data); + + default: + LOG_WARN("%s : unhandled event:%s\n", __FUNCTION__, + dump_av_sm_event_name(event)); + return FALSE; + + } + return TRUE; +} + +/***************************************************************************** +** +** Function btc_av_state_started_handler +** +** Description Handles AV events while A2DP stream is started +** +** Returns TRUE if event was processed, FALSE otherwise +** +*******************************************************************************/ + +static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data) +{ + tBTA_AV *p_av = (tBTA_AV *)p_data; + + LOG_DEBUG("%s event:%s flags %x\n", __FUNCTION__, + dump_av_sm_event_name(event), btc_av_cb.flags); + + switch (event) { + case BTC_SM_ENTER_EVT: + + /* we are again in started state, clear any remote suspend flags */ + btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND; + + btc_report_audio_state(ESP_A2D_AUDIO_STATE_STARTED, &(btc_av_cb.peer_bda)); + + /* increase the a2dp consumer task priority temporarily when start + ** audio playing, to avoid overflow the audio packet queue. */ + adjust_priority_a2dp(TRUE); + + break; + + case BTC_SM_EXIT_EVT: + /* restore the a2dp consumer task priority when stop audio playing. */ + adjust_priority_a2dp(FALSE); + + break; + + case BTC_AV_START_STREAM_REQ_EVT: + break; + + /* fixme -- use suspend = true always to work around issue with BTA AV */ + case BTC_AV_STOP_STREAM_REQ_EVT: + case BTC_AV_SUSPEND_STREAM_REQ_EVT: + + /* set pending flag to ensure btc task is not trying to restart + stream while suspend is in progress */ + btc_av_cb.flags |= BTC_AV_FLAG_LOCAL_SUSPEND_PENDING; + + /* if we were remotely suspended but suspend locally, local suspend + always overrides */ + btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND; + + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + btc_a2dp_set_rx_flush(TRUE); + btc_a2dp_on_stopped(NULL); + } + + BTA_AvStop(TRUE); + break; + + case BTC_AV_DISCONNECT_REQ_EVT: + + /* request avdtp to close */ + BTA_AvClose(btc_av_cb.bta_handle); + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + BTA_AvCloseRc(btc_av_cb.bta_handle); + } + + /* inform the application that we are disconnecting */ + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTING, &(btc_av_cb.peer_bda), 0); + + /* wait in closing state until fully closed */ + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_CLOSING); + break; + + case BTA_AV_SUSPEND_EVT: + + LOG_INFO("BTA_AV_SUSPEND_EVT status %d, init %d\n", + p_av->suspend.status, p_av->suspend.initiator); + + /* a2dp suspended, stop media task until resumed */ + btc_a2dp_on_suspended(&p_av->suspend); + + /* if not successful, remain in current state */ + if (p_av->suspend.status != BTA_AV_SUCCESS) { + btc_av_cb.flags &= ~BTC_AV_FLAG_LOCAL_SUSPEND_PENDING; + + return FALSE; + } + + if (p_av->suspend.initiator != TRUE) { + /* remote suspend, notify HAL and await audioflinger to + suspend/stop stream */ + + /* set remote suspend flag to block media task from restarting + stream only if we did not already initiate a local suspend */ + if ((btc_av_cb.flags & BTC_AV_FLAG_LOCAL_SUSPEND_PENDING) == 0) { + btc_av_cb.flags |= BTC_AV_FLAG_REMOTE_SUSPEND; + } + + btc_report_audio_state(ESP_A2D_AUDIO_STATE_REMOTE_SUSPEND, &(btc_av_cb.peer_bda)); + } else { + btc_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btc_av_cb.peer_bda)); + } + + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_OPENED); + + /* suspend completed and state changed, clear pending status */ + btc_av_cb.flags &= ~BTC_AV_FLAG_LOCAL_SUSPEND_PENDING; + break; + + case BTA_AV_STOP_EVT: + + btc_av_cb.flags |= BTC_AV_FLAG_PENDING_STOP; + btc_a2dp_on_stopped(&p_av->suspend); + + btc_report_audio_state(ESP_A2D_AUDIO_STATE_STOPPED, &(btc_av_cb.peer_bda)); + + /* if stop was successful, change state to open */ + if (p_av->suspend.status == BTA_AV_SUCCESS) { + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_OPENED); + } + + break; + + case BTA_AV_CLOSE_EVT: { + + btc_av_cb.flags |= BTC_AV_FLAG_PENDING_STOP; + + /* avdtp link is closed */ + btc_a2dp_on_stopped(NULL); + + tBTA_AV_CLOSE *close = (tBTA_AV_CLOSE *)p_data; + /* inform the application that we are disconnected */ + btc_report_connection_state(ESP_A2D_CONNECTION_STATE_DISCONNECTED, &(btc_av_cb.peer_bda), + close->disc_rsn); + + btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE); + break; + } + + CHECK_RC_EVENT(event, p_data); + + default: + LOG_WARN("%s : unhandled event:%s\n", __FUNCTION__, + dump_av_sm_event_name(event)); + return FALSE; + + } + return TRUE; +} + +/***************************************************************************** +** Local event handlers +******************************************************************************/ + +void btc_av_event_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + tBTA_AV *av_src = (tBTA_AV *)p_src; + tBTA_AV *av_dest = (tBTA_AV *)p_dest; + + // First copy the structure + memcpy(p_dest, p_src, sizeof(tBTA_AV)); + + switch (msg->act) { + case BTA_AV_META_MSG_EVT: + if (av_src->meta_msg.p_data && av_src->meta_msg.len) { + av_dest->meta_msg.p_data = osi_calloc(av_src->meta_msg.len); + assert(av_dest->meta_msg.p_data); + memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data, av_src->meta_msg.len); + } + + if (av_src->meta_msg.p_msg) { + av_dest->meta_msg.p_msg = osi_calloc(sizeof(tAVRC_MSG)); + assert(av_dest->meta_msg.p_msg); + memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg, sizeof(tAVRC_MSG)); + + if (av_src->meta_msg.p_msg->vendor.p_vendor_data && + av_src->meta_msg.p_msg->vendor.vendor_len) { + av_dest->meta_msg.p_msg->vendor.p_vendor_data = osi_calloc( + av_src->meta_msg.p_msg->vendor.vendor_len); + assert(av_dest->meta_msg.p_msg->vendor.p_vendor_data); + memcpy(av_dest->meta_msg.p_msg->vendor.p_vendor_data, + av_src->meta_msg.p_msg->vendor.p_vendor_data, + av_src->meta_msg.p_msg->vendor.vendor_len); + } + } + break; + + default: + break; + } +} + +static void btc_av_event_free_data(btc_sm_event_t event, void *p_data) +{ + switch (event) { + case BTA_AV_META_MSG_EVT: { + tBTA_AV *av = (tBTA_AV *)p_data; + if (av->meta_msg.p_data) { + osi_free(av->meta_msg.p_data); + } + + if (av->meta_msg.p_msg) { + if (av->meta_msg.p_msg->vendor.p_vendor_data) { + osi_free(av->meta_msg.p_msg->vendor.p_vendor_data); + } + osi_free(av->meta_msg.p_msg); + } + } + break; + + default: + break; + } +} + +static void bte_av_callback(tBTA_AV_EVT event, tBTA_AV *p_data) +{ + bt_status_t stat; + btc_msg_t msg; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_A2DP; + msg.act = (uint8_t) event; + stat = btc_transfer_context(&msg, p_data, sizeof(tBTA_AV), btc_av_event_deep_copy); + + if (stat) { + LOG_ERROR("%s transfer failed\n", __func__); + } +} + +static void bte_av_media_callback(tBTA_AV_EVT event, tBTA_AV_MEDIA *p_data) +{ + btc_sm_state_t state; + UINT8 que_len; + tA2D_STATUS a2d_status; + tA2D_SBC_CIE sbc_cie; + + if (event == BTA_AV_MEDIA_DATA_EVT) { /* Switch to BTC_MEDIA context */ + state = btc_sm_get_state(btc_av_cb.sm_handle); + if ( (state == BTC_AV_STATE_STARTED) || /* send SBC packets only in Started State */ + (state == BTC_AV_STATE_OPENED) ) { + que_len = btc_media_sink_enque_buf((BT_HDR *)p_data); + LOG_DEBUG(" Packets in Que %d\n", que_len); + } else { + return; + } + } + + if (event == BTA_AV_MEDIA_SINK_CFG_EVT) { + /* send a command to BT Media Task */ + btc_reset_decoder((UINT8 *)p_data); + + /* currently only supportes SBC */ + a2d_status = A2D_ParsSbcInfo(&sbc_cie, (UINT8 *)p_data, FALSE); + if (a2d_status == A2D_SUCCESS) { + btc_msg_t msg; + btc_av_args_t arg; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_A2DP; + msg.act = BTC_AV_SINK_CONFIG_REQ_EVT; + + memset(&arg, 0, sizeof(btc_av_args_t)); + arg.mcc.type = ESP_A2D_MCT_SBC; + memcpy(arg.mcc.cie.sbc, (uint8_t *)p_data + 3, ESP_A2D_CIE_LEN_SBC); + btc_transfer_context(&msg, &arg, sizeof(btc_av_args_t), NULL); + } else { + LOG_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status); + } + } +} +/******************************************************************************* +** +** Function btc_av_init +** +** Description Initializes btc AV if not already done +** +** Returns bt_status_t +** +*******************************************************************************/ + +bt_status_t btc_av_init(void) +{ + if (btc_av_cb.sm_handle == NULL) { + if (!btc_a2dp_start_media_task()) { + return BT_STATUS_FAIL; + } + + /* Also initialize the AV state machine */ + btc_av_cb.sm_handle = + btc_sm_init((const btc_sm_handler_t *)btc_av_state_handlers, BTC_AV_STATE_IDLE); + + btc_dm_enable_service(BTA_A2DP_SOURCE_SERVICE_ID); +#if (BTA_AV_SINK_INCLUDED == TRUE) + btc_dm_enable_service(BTA_A2DP_SINK_SERVICE_ID); +#endif + + btc_a2dp_on_init(); + } + + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function init_sink +** +** Description Initializes the AV interface for sink mode +** +** Returns bt_status_t +** +*******************************************************************************/ +bt_status_t btc_a2d_sink_init(void) +{ + LOG_DEBUG("%s()\n", __func__); + + return btc_av_init(); +} + +/******************************************************************************* +** +** Function connect +** +** Description Establishes the AV signalling channel with the remote headset +** +** Returns bt_status_t +** +*******************************************************************************/ + +static bt_status_t connect_int(bt_bdaddr_t *bd_addr, uint16_t uuid) +{ + btc_av_connect_req_t connect_req; + connect_req.target_bda = bd_addr; + connect_req.uuid = uuid; + LOG_DEBUG("%s\n", __FUNCTION__); + + btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_CONNECT_REQ_EVT, (char *)&connect_req); + + return BT_STATUS_SUCCESS; +} + +bt_status_t btc_a2d_sink_connect(bt_bdaddr_t *remote_bda) +{ + LOG_DEBUG("%s\n", __FUNCTION__); + CHECK_BTAV_INIT(); + + return btc_queue_connect(UUID_SERVCLASS_AUDIO_SINK, remote_bda, connect_int); +} + +/******************************************************************************* +** +** Function cleanup +** +** Description Shuts down the AV interface and does the cleanup +** +** Returns None +** +*******************************************************************************/ +static void btc_a2d_sink_deinit(void) +{ + LOG_DEBUG("%s\n", __FUNCTION__); + + btc_a2dp_stop_media_task(); + + btc_dm_disable_service(BTA_A2DP_SOURCE_SERVICE_ID); +#if (BTA_AV_SINK_INCLUDED == TRUE) + btc_dm_disable_service(BTA_A2DP_SINK_SERVICE_ID); +#endif + + /* Also shut down the AV state machine */ + btc_sm_shutdown(btc_av_cb.sm_handle); + btc_av_cb.sm_handle = NULL; +} + +/******************************************************************************* +** +** Function btc_av_get_sm_handle +** +** Description Fetches current av SM handle +** +** Returns None +** +*******************************************************************************/ + +btc_sm_handle_t btc_av_get_sm_handle(void) +{ + return btc_av_cb.sm_handle; +} + +/******************************************************************************* +** +** Function btc_av_stream_ready +** +** Description Checks whether AV is ready for starting a stream +** +** Returns None +** +*******************************************************************************/ + +BOOLEAN btc_av_stream_ready(void) +{ + btc_sm_state_t state = btc_sm_get_state(btc_av_cb.sm_handle); + + LOG_DEBUG("btc_av_stream_ready : sm hdl %d, state %d, flags %x\n", + (int)btc_av_cb.sm_handle, state, btc_av_cb.flags); + + /* check if we are remotely suspended or stop is pending */ + if (btc_av_cb.flags & (BTC_AV_FLAG_REMOTE_SUSPEND | BTC_AV_FLAG_PENDING_STOP)) { + return FALSE; + } + + return (state == BTC_AV_STATE_OPENED); +} + +/******************************************************************************* +** +** Function btc_av_stream_started_ready +** +** Description Checks whether AV ready for media start in streaming state +** +** Returns None +** +*******************************************************************************/ + +BOOLEAN btc_av_stream_started_ready(void) +{ + btc_sm_state_t state = btc_sm_get_state(btc_av_cb.sm_handle); + + LOG_DEBUG("btc_av_stream_started : sm hdl %d, state %d, flags %x\n", + (int)btc_av_cb.sm_handle, state, btc_av_cb.flags); + + /* disallow media task to start if we have pending actions */ + if (btc_av_cb.flags & (BTC_AV_FLAG_LOCAL_SUSPEND_PENDING | BTC_AV_FLAG_REMOTE_SUSPEND + | BTC_AV_FLAG_PENDING_STOP)) { + return FALSE; + } + + return (state == BTC_AV_STATE_STARTED); +} + +/******************************************************************************* +** +** Function btc_dispatch_sm_event +** +** Description Send event to AV statemachine +** +** Returns None +** +*******************************************************************************/ + +/* used to pass events to AV statemachine from other tasks */ +void btc_dispatch_sm_event(btc_av_sm_event_t event, void *p_data, int len) +{ + btc_msg_t msg; + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_A2DP; + msg.act = event; + btc_transfer_context(&msg, p_data, len, NULL); +} + +/******************************************************************************* +** +** Function btc_av_execute_service +** +** Description Initializes/Shuts down the service +** +** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btc_av_execute_service(BOOLEAN b_enable) +{ + if (b_enable) { + /* TODO: Removed BTA_SEC_AUTHORIZE since the Java/App does not + * handle this request in order to allow incoming connections to succeed. + * We need to put this back once support for this is added */ + + /* Added BTA_AV_FEAT_NO_SCO_SSPD - this ensures that the BTA does not + * auto-suspend av streaming on AG events(SCO or Call). The suspend shall + * be initiated by the app/audioflinger layers */ + BTA_AvEnable(BTA_SEC_AUTHENTICATE, (BTA_AV_FEAT_NO_SCO_SSPD) + // | BTA_AV_FEAT_RCTG | BTA_AV_FEAT_METADATA | BTA_AV_FEAT_VENDOR + | BTA_AV_FEAT_RCCT | BTA_AV_FEAT_ADV_CTRL, + bte_av_callback); + BTA_AvRegister(BTA_AV_CHNL_AUDIO, BTC_AV_SERVICE_NAME, 0, bte_av_media_callback, &bta_av_a2d_cos); + } else { + BTA_AvDeregister(btc_av_cb.bta_handle); + BTA_AvDisable(); + } + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function btc_av_sink_execute_service +** +** Description Initializes/Shuts down the service +** +** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise +** +*******************************************************************************/ +bt_status_t btc_av_sink_execute_service(BOOLEAN b_enable) +{ +#if (BTA_AV_SINK_INCLUDED == TRUE) + BTA_AvEnable_Sink(b_enable); +#endif + return BT_STATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function btc_av_is_connected +** +** Description Checks if av has a connected sink +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN btc_av_is_connected(void) +{ + btc_sm_state_t state = btc_sm_get_state(btc_av_cb.sm_handle); + return ((state == BTC_AV_STATE_OPENED) || (state == BTC_AV_STATE_STARTED)); +} + +/******************************************************************************* +** +** Function btc_av_is_peer_edr +** +** Description Check if the connected a2dp device supports +** EDR or not. Only when connected this function +** will accurately provide a true capability of +** remote peer. If not connected it will always be false. +** +** Returns TRUE if remote device is capable of EDR +** +*******************************************************************************/ +BOOLEAN btc_av_is_peer_edr(void) +{ + BTC_ASSERTC(btc_av_is_connected(), "No active a2dp connection\n", 0); + + if (btc_av_cb.edr) { + return TRUE; + } else { + return FALSE; + } +} + +/****************************************************************************** +** +** Function btc_av_clear_remote_suspend_flag +** +** Description Clears btc_av_cb.flags if BTC_AV_FLAG_REMOTE_SUSPEND is set +** +** Returns void +******************************************************************************/ +void btc_av_clear_remote_suspend_flag(void) +{ + LOG_DEBUG("%s: flag :%x\n", __func__, btc_av_cb.flags); + btc_av_cb.flags &= ~BTC_AV_FLAG_REMOTE_SUSPEND; +} + +void btc_a2dp_call_handler(btc_msg_t *msg) +{ + btc_av_args_t *arg = (btc_av_args_t *)(msg->arg); + switch (msg->act) { + case BTC_AV_SINK_CONFIG_REQ_EVT: { + btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, (void *)(msg->arg)); + break; + } + case BTC_AV_SINK_API_INIT_EVT: { + btc_a2d_sink_init(); + // todo: callback to application + break; + } + case BTC_AV_SINK_API_DEINIT_EVT: { + btc_a2d_sink_deinit(); + // todo: callback to application + break; + } + case BTC_AV_SINK_API_CONNECT_EVT: { + btc_a2d_sink_connect(&arg->connect); + // todo: callback to application + break; + } + case BTC_AV_SINK_API_DISCONNECT_EVT: { + CHECK_BTAV_INIT(); + btc_sm_dispatch(btc_av_cb.sm_handle, BTC_AV_DISCONNECT_REQ_EVT, NULL); + break; + } + case BTC_AV_SINK_API_REG_DATA_CB_EVT: { + btc_a2dp_sink_reg_data_cb(arg->data_cb); + break; + } + default: + LOG_WARN("%s : unhandled event: %d\n", __FUNCTION__, msg->act); + } +} + +void btc_a2dp_cb_handler(btc_msg_t *msg) +{ + btc_sm_dispatch(btc_av_cb.sm_handle, msg->act, (void *)(msg->arg)); + btc_av_event_free_data(msg->act, msg->arg); +} + +#endif /* #if BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_media_task.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_media_task.c new file mode 100644 index 0000000000..3d4352d2ef --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_media_task.c @@ -0,0 +1,1015 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + +/****************************************************************************** + ** + ** Name: btc_media_task.c + ** + ** Description: This is the multimedia module for the BTC system. It + ** contains task implementations AV, HS and HF profiles + ** audio & video processing + ** + ******************************************************************************/ + +#include "bt_target.h" +#include "bt_trace.h" +#include +#include +#include +#include "fixed_queue.h" +#include "gki.h" +#include "bta_api.h" +#include "btu.h" +#include "bta_sys.h" +#include "bta_sys_int.h" +#include "bta_av_api.h" +#include "a2d_api.h" +#include "a2d_sbc.h" +#include "a2d_int.h" +#include "bta_av_sbc.h" +#include "bta_av_ci.h" +#include "l2c_api.h" +#include "btc_av_co.h" +#include "btc_media.h" +#include "alarm.h" +#include "bt_trace.h" +#include "thread.h" +#include "bt_defs.h" +#include "btc_av.h" +#include "btc_sm.h" +#include "btc_util.h" +#include "allocator.h" +#include "bt_utils.h" +#include "esp_a2dp_api.h" + +// #if (BTA_AV_SINK_INCLUDED == TRUE) +#include "oi_codec_sbc.h" +#include "oi_status.h" +// #endif + +#if BTC_AV_INCLUDED + +// #if (BTA_AV_SINK_INCLUDED == TRUE) +OI_CODEC_SBC_DECODER_CONTEXT context; +OI_UINT32 contextData[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)]; +OI_INT16 pcmData[15 * SBC_MAX_SAMPLES_PER_FRAME * SBC_MAX_CHANNELS]; +// #endif + +/***************************************************************************** + ** Constants + *****************************************************************************/ + +/* BTC media cmd event definition : BTC_MEDIA_TASK_CMD */ +enum { + BTC_MEDIA_FLUSH_AA_RX = 1, + BTC_MEDIA_AUDIO_SINK_CFG_UPDATE, + BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK +}; + +enum { + MEDIA_TASK_STATE_OFF = 0, + MEDIA_TASK_STATE_ON = 1, + MEDIA_TASK_STATE_SHUTTING_DOWN = 2 +}; + +enum { + SIG_MEDIA_TASK_INIT = 0xf0, + SIG_MEDIA_TASK_CLEAN_UP = 0xf1, + SIG_MEDIA_TASK_AVK_DATA_READY = 0xf2, + SIG_MEDIA_TASK_CMD_READY = 0xf3 +}; + +/* + * CONGESTION COMPENSATION CTRL :: + * + * Thus setting controls how many buffers we will hold in media task + * during temp link congestion. Together with the stack buffer queues + * it controls much temporary a2dp link congestion we can + * compensate for. It however also depends on the default run level of sinks + * jitterbuffers. Depending on type of sink this would vary. + * Ideally the (SRC) max tx buffer capacity should equal the sinks + * jitterbuffer runlevel including any intermediate buffers on the way + * towards the sinks codec. + */ + +/* fixme -- define this in pcm time instead of buffer count */ + +/* The typical runlevel of the tx queue size is ~1 buffer + but due to link flow control or thread preemption in lower + layers we might need to temporarily buffer up data */ + +/* 5 frames is equivalent to 6.89*5*2.9 ~= 100 ms @ 44.1 khz, 20 ms mediatick */ +#define MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ (5) + +#define MEDIA_DATA_Q_LEN (1) +#define MEDIA_CTRL_Q_LEN (5) +#define COMBINED_MEDIA_Q_LEN (MEDIA_DATA_Q_LEN + MEDIA_CTRL_Q_LEN) + +typedef struct { + UINT16 num_frames_to_be_processed; + UINT16 len; + UINT16 offset; + UINT16 layer_specific; +} tBT_SBC_HDR; + +typedef struct { + BUFFER_Q RxSbcQ; + void *av_sm_hdl; + UINT8 peer_sep; + UINT8 busy_level; + BOOLEAN rx_flush; /* discards any incoming data when true */ + BOOLEAN data_channel_open; + UINT8 channel_count; + UINT32 sample_rate; +} tBTC_MEDIA_CB; + +// #if (BTA_AV_SINK_INCLUDED == TRUE) +extern OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, + const OI_BYTE **frameData, + unsigned long *frameBytes, + OI_INT16 *pcmData, + unsigned long *pcmBytes); +extern OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context, + unsigned long *decoderData, + unsigned long decoderDataBytes, + OI_UINT8 maxChannels, + OI_UINT8 pcmStride, + OI_BOOL enhanced); +// #endif + +static void btc_media_flush_q(BUFFER_Q *p_q); +static void btc_media_task_aa_rx_flush(void); +static const char *dump_media_event(UINT16 event); +static void btc_media_thread_handle_cmd(fixed_queue_t *queue); + +/* Handle incoming media packets A2DP SINK streaming*/ +static void btc_media_task_handle_inc_media(tBT_SBC_HDR *p_msg); +static void btc_media_task_aa_handle_decoder_reset(BT_HDR *p_msg); +static void btc_media_task_aa_handle_clear_track(void); +BOOLEAN btc_media_task_clear_track(void); +static void btc_media_task_handler(void *arg); + +static void btc_media_task_avk_data_ready(UNUSED_ATTR void *context); +static void btc_media_thread_init(UNUSED_ATTR void *context); +static void btc_media_thread_cleanup(UNUSED_ATTR void *context); + +static tBTC_MEDIA_CB btc_media_cb; +static int media_task_running = MEDIA_TASK_STATE_OFF; +static fixed_queue_t *btc_media_cmd_msg_queue = NULL; +static xTaskHandle xBtcMediaTaskHandle = NULL; +static QueueHandle_t xBtcMediaDataQueue = NULL; +static QueueHandle_t xBtcMediaCtrlQueue = NULL; +static QueueSetHandle_t xBtcMediaQueueSet; +static esp_a2d_data_cb_t bt_av_sink_data_callback = NULL; + +void btc_a2dp_sink_reg_data_cb(esp_a2d_data_cb_t callback) +{ + // todo: critical section protection + bt_av_sink_data_callback = callback; +} + +static inline void btc_a2d_data_cb_to_app(const uint8_t *data, uint32_t len) +{ + // todo: critical section protection + if (bt_av_sink_data_callback) { + bt_av_sink_data_callback(data, len); + } +} + +/***************************************************************************** + ** Misc helper functions + *****************************************************************************/ +UNUSED_ATTR static const char *dump_media_event(UINT16 event) +{ + switch (event) { + CASE_RETURN_STR(BTC_MEDIA_FLUSH_AA_RX) + CASE_RETURN_STR(BTC_MEDIA_AUDIO_SINK_CFG_UPDATE) + CASE_RETURN_STR(BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK) + + default: + return "UNKNOWN MEDIA EVENT"; + } +} + +/***************************************************************************** + ** BTC ADAPTATION + *****************************************************************************/ + +static void btc_media_ctrl_post(uint32_t sig) +{ + BtTaskEvt_t *evt = (BtTaskEvt_t *)osi_malloc(sizeof(BtTaskEvt_t)); + if (evt == NULL) { + return; + } + + evt->sig = sig; + evt->par = 0; + + if (xQueueSend(xBtcMediaCtrlQueue, &evt, 10 / portTICK_RATE_MS) != pdTRUE) { + APPL_TRACE_WARNING("xBtcMediaCtrlQueue failed, sig 0x%x\n", sig); + } +} + +static void btc_media_data_post(void) +{ + void *evt; + if (xQueueSend(xBtcMediaDataQueue, &evt, 0) != pdTRUE) { + APPL_TRACE_DEBUG("Media data Q filled\n"); + } +} + +static void btc_media_ctrl_handler(BtTaskEvt_t *e) +{ + if (e == NULL) { + return; + } + switch (e->sig) { + case SIG_MEDIA_TASK_CMD_READY: + fixed_queue_process(btc_media_cmd_msg_queue); + break; + case SIG_MEDIA_TASK_INIT: + btc_media_thread_init(NULL); + break; + case SIG_MEDIA_TASK_CLEAN_UP: + btc_media_thread_cleanup(NULL); + break; + default: + APPL_TRACE_WARNING("media task unhandled evt: 0x%x\n", e->sig); + } +} + + +static void btc_media_task_handler(void *arg) +{ + QueueSetMemberHandle_t xActivatedMember; + BtTaskEvt_t *e = NULL; + for (;;) { + xActivatedMember = xQueueSelectFromSet(xBtcMediaQueueSet, portMAX_DELAY); + if (xActivatedMember == xBtcMediaDataQueue) { + xQueueReceive(xActivatedMember, &e, 0); + btc_media_task_avk_data_ready(NULL); + } else if (xActivatedMember == xBtcMediaCtrlQueue) { + xQueueReceive(xActivatedMember, &e, 0); + btc_media_ctrl_handler(e); + osi_free(e); + } + } +} + +bool btc_a2dp_start_media_task(void) +{ + if (media_task_running != MEDIA_TASK_STATE_OFF) { + APPL_TRACE_ERROR("warning : media task already running"); + return false; + } + + APPL_TRACE_EVENT("## A2DP START MEDIA THREAD ##"); + + xBtcMediaQueueSet = xQueueCreateSet(COMBINED_MEDIA_Q_LEN); + configASSERT(xBtcMediaQueueSet); + xBtcMediaDataQueue = xQueueCreate(MEDIA_DATA_Q_LEN, sizeof(void *)); + configASSERT(xBtcMediaDataQueue); + xQueueAddToSet(xBtcMediaDataQueue, xBtcMediaQueueSet); + + xBtcMediaCtrlQueue = xQueueCreate(MEDIA_CTRL_Q_LEN, sizeof(void *)); + configASSERT(xBtcMediaCtrlQueue); + xQueueAddToSet(xBtcMediaCtrlQueue, xBtcMediaQueueSet); + + if (!xBtcMediaDataQueue || !xBtcMediaCtrlQueue || !xBtcMediaQueueSet ) { + goto error_exit; + } + + xTaskCreatePinnedToCore(btc_media_task_handler, "BtcMediaT\n", 2048, NULL, configMAX_PRIORITIES - 3, &xBtcMediaTaskHandle, 0); + if (xBtcMediaTaskHandle == NULL) { + goto error_exit; + } + + btc_media_cmd_msg_queue = fixed_queue_new(SIZE_MAX); + if (btc_media_cmd_msg_queue == NULL) { + goto error_exit; + } + fixed_queue_register_dequeue(btc_media_cmd_msg_queue, btc_media_thread_handle_cmd); + btc_media_ctrl_post(SIG_MEDIA_TASK_INIT); + + APPL_TRACE_EVENT("## A2DP MEDIA THREAD STARTED ##\n"); + + return true; + +error_exit:; + APPL_TRACE_ERROR("%s unable to start up media thread\n", __func__); + + if (xBtcMediaTaskHandle != NULL) { + vTaskDelete(xBtcMediaTaskHandle); + xBtcMediaTaskHandle = NULL; + } + + if (xBtcMediaDataQueue) { + vQueueDelete(xBtcMediaDataQueue); + xBtcMediaDataQueue = NULL; + } + if (xBtcMediaCtrlQueue) { + vQueueDelete(xBtcMediaCtrlQueue); + xBtcMediaCtrlQueue = NULL; + } + + fixed_queue_free(btc_media_cmd_msg_queue, NULL); + btc_media_cmd_msg_queue = NULL; + return false; +} + +void btc_a2dp_stop_media_task(void) +{ + APPL_TRACE_EVENT("## A2DP STOP MEDIA THREAD ##\n"); + + // Exit thread + btc_media_ctrl_post(SIG_MEDIA_TASK_CLEAN_UP); + // TODO: wait until CLEAN up is done, then do task delete + vTaskDelete(xBtcMediaTaskHandle); + xBtcMediaTaskHandle = NULL; + + vQueueDelete(xBtcMediaDataQueue); + xBtcMediaDataQueue = NULL; + + vQueueDelete(xBtcMediaCtrlQueue); + xBtcMediaCtrlQueue = NULL; + + fixed_queue_free(btc_media_cmd_msg_queue, NULL); + btc_media_cmd_msg_queue = NULL; +} + +/***************************************************************************** +** +** Function btc_a2dp_on_init +** +** Description +** +** Returns +** +*******************************************************************************/ +void btc_a2dp_on_init(void) +{ + //tput_mon(1, 0, 1); +} + +/***************************************************************************** +** +** Function btc_a2dp_setup_codec +** +** Description +** +** Returns +** +*******************************************************************************/ + +void btc_a2dp_setup_codec(void) +{ + tBTC_AV_MEDIA_FEEDINGS media_feeding; + tBTC_STATUS status; + + APPL_TRACE_EVENT("## A2DP SETUP CODEC ##\n"); + + GKI_disable(); + + /* for now hardcode 44.1 khz 16 bit stereo PCM format */ + media_feeding.cfg.pcm.sampling_freq = 44100; + media_feeding.cfg.pcm.bit_per_sample = 16; + media_feeding.cfg.pcm.num_channel = 2; + media_feeding.format = BTC_AV_CODEC_PCM; + + bta_av_co_audio_set_codec(&media_feeding, &status); + + GKI_enable(); +} + +/***************************************************************************** +** +** Function btc_a2dp_on_idle +** +** Description +** +** Returns +** +*******************************************************************************/ + +void btc_a2dp_on_idle(void) +{ + APPL_TRACE_EVENT("## ON A2DP IDLE ##\n"); + + bta_av_co_init(); + if (btc_media_cb.peer_sep == AVDT_TSEP_SRC) { + btc_media_cb.rx_flush = TRUE; + btc_media_task_aa_rx_flush_req(); + btc_media_task_clear_track(); + APPL_TRACE_DEBUG("Stopped BT track"); + } +} + +/******************************************************************************* + ** + ** Function btc_media_task_clear_track + ** + ** Description + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +BOOLEAN btc_media_task_clear_track(void) +{ + BT_HDR *p_buf; + + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) { + return FALSE; + } + + p_buf->event = BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK; + + fixed_queue_enqueue(btc_media_cmd_msg_queue, p_buf); + btc_media_ctrl_post(SIG_MEDIA_TASK_CMD_READY); + return TRUE; +} + +/***************************************************************************** +** +** Function btc_reset_decoder +** +** Description +** +** Returns +** +*******************************************************************************/ + +void btc_reset_decoder(UINT8 *p_av) +{ + APPL_TRACE_EVENT("btc_reset_decoder"); + APPL_TRACE_DEBUG("btc_reset_decoder p_codec_info[%x:%x:%x:%x:%x:%x]\n", + p_av[1], p_av[2], p_av[3], + p_av[4], p_av[5], p_av[6]); + + tBTC_MEDIA_SINK_CFG_UPDATE *p_buf; + if (NULL == (p_buf = GKI_getbuf(sizeof(tBTC_MEDIA_SINK_CFG_UPDATE)))) { + APPL_TRACE_ERROR("btc_reset_decoder No Buffer "); + return; + } + + memcpy(p_buf->codec_info, p_av, AVDT_CODEC_SIZE); + p_buf->hdr.event = BTC_MEDIA_AUDIO_SINK_CFG_UPDATE; + + fixed_queue_enqueue(btc_media_cmd_msg_queue, p_buf); + btc_media_ctrl_post(SIG_MEDIA_TASK_CMD_READY); +} + +/***************************************************************************** +** +** Function btc_a2dp_on_stopped +** +** Description +** +** Returns +** +*******************************************************************************/ + +void btc_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av) +{ + APPL_TRACE_EVENT("## ON A2DP STOPPED ##\n"); + if (btc_media_cb.peer_sep == AVDT_TSEP_SRC) { /* Handling for A2DP SINK cases*/ + btc_media_cb.rx_flush = TRUE; + btc_media_task_aa_rx_flush_req(); + btc_media_cb.data_channel_open = FALSE; + return; + } +} + +/***************************************************************************** +** +** Function btc_a2dp_on_suspended +** +** Description +** +** Returns +** +*******************************************************************************/ + +void btc_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av) +{ + APPL_TRACE_EVENT("## ON A2DP SUSPENDED ##\n"); + if (btc_media_cb.peer_sep == AVDT_TSEP_SRC) { + btc_media_cb.rx_flush = TRUE; + btc_media_task_aa_rx_flush_req(); + return; + } +} + +/* when true media task discards any rx frames */ +void btc_a2dp_set_rx_flush(BOOLEAN enable) +{ + APPL_TRACE_EVENT("## DROP RX %d ##\n", enable); + btc_media_cb.rx_flush = enable; +} + +static void btc_media_task_avk_data_ready(UNUSED_ATTR void *context) +{ + UINT8 count; + tBT_SBC_HDR *p_msg; + + count = btc_media_cb.RxSbcQ._count; + if (0 == count) { + APPL_TRACE_DEBUG(" QUE EMPTY "); + } else { + if (btc_media_cb.rx_flush == TRUE) { + btc_media_flush_q(&(btc_media_cb.RxSbcQ)); + return; + } + + while ((p_msg = (tBT_SBC_HDR *)GKI_getfirst(&(btc_media_cb.RxSbcQ))) != NULL ) { + btc_media_task_handle_inc_media(p_msg); + p_msg = GKI_dequeue(&(btc_media_cb.RxSbcQ)); + if ( p_msg == NULL ) { + APPL_TRACE_ERROR("Insufficient data in que "); + break; + } + GKI_freebuf(p_msg); + } + APPL_TRACE_DEBUG(" Process Frames - "); + } +} + +static void btc_media_thread_init(UNUSED_ATTR void *context) +{ + APPL_TRACE_EVENT("%s\n", __func__); + memset(&btc_media_cb, 0, sizeof(btc_media_cb)); + btc_media_cb.av_sm_hdl = btc_av_get_sm_handle(); + raise_priority_a2dp(TASK_HIGH_MEDIA); + media_task_running = MEDIA_TASK_STATE_ON; +} + +static void btc_media_thread_cleanup(UNUSED_ATTR void *context) +{ + /* make sure no channels are restarted while shutting down */ + media_task_running = MEDIA_TASK_STATE_SHUTTING_DOWN; + + btc_media_cb.data_channel_open = FALSE; + /* Clear media task flag */ + media_task_running = MEDIA_TASK_STATE_OFF; +} + +/******************************************************************************* + ** + ** Function btc_media_flush_q + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btc_media_flush_q(BUFFER_Q *p_q) +{ + while (!GKI_queue_is_empty(p_q)) { + GKI_freebuf(GKI_dequeue(p_q)); + } +} + +static void btc_media_thread_handle_cmd(fixed_queue_t *queue) +{ + BT_HDR *p_msg; + while (!fixed_queue_is_empty(queue)) { + p_msg = (BT_HDR *)fixed_queue_dequeue(queue); + APPL_TRACE_VERBOSE("btc_media_thread_handle_cmd : %d %s\n", p_msg->event, + dump_media_event(p_msg->event)); + + switch (p_msg->event) { + case BTC_MEDIA_AUDIO_SINK_CFG_UPDATE: + btc_media_task_aa_handle_decoder_reset(p_msg); + break; + case BTC_MEDIA_AUDIO_SINK_CLEAR_TRACK: + btc_media_task_aa_handle_clear_track(); + break; + case BTC_MEDIA_FLUSH_AA_RX: + btc_media_task_aa_rx_flush(); + break; + default: + APPL_TRACE_ERROR("ERROR in %s unknown event %d\n", __func__, p_msg->event); + } + GKI_freebuf(p_msg); + APPL_TRACE_VERBOSE("%s: %s DONE\n", __func__, dump_media_event(p_msg->event)); + } +} + +/******************************************************************************* + ** + ** Function btc_media_task_handle_inc_media + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btc_media_task_handle_inc_media(tBT_SBC_HDR *p_msg) +{ + UINT8 *sbc_start_frame = ((UINT8 *)(p_msg + 1) + p_msg->offset + 1); + int count; + UINT32 pcmBytes, availPcmBytes; + OI_INT16 *pcmDataPointer = pcmData; /*Will be overwritten on next packet receipt*/ + OI_STATUS status; + int num_sbc_frames = p_msg->num_frames_to_be_processed; + UINT32 sbc_frame_len = p_msg->len - 1; + availPcmBytes = 2 * sizeof(pcmData); + + if ((btc_media_cb.peer_sep == AVDT_TSEP_SNK) || (btc_media_cb.rx_flush)) { + APPL_TRACE_DEBUG(" State Changed happened in this tick "); + return; + } + + // ignore data if no one is listening + if (!btc_media_cb.data_channel_open) { + return; + } + + APPL_TRACE_DEBUG("Number of sbc frames %d, frame_len %d\n", num_sbc_frames, sbc_frame_len); + + for (count = 0; count < num_sbc_frames && sbc_frame_len != 0; count ++) { + pcmBytes = availPcmBytes; + status = OI_CODEC_SBC_DecodeFrame(&context, (const OI_BYTE **)&sbc_start_frame, + (OI_UINT32 *)&sbc_frame_len, + (OI_INT16 *)pcmDataPointer, + (OI_UINT32 *)&pcmBytes); + if (!OI_SUCCESS(status)) { + APPL_TRACE_ERROR("Decoding failure: %d\n", status); + break; + } + availPcmBytes -= pcmBytes; + pcmDataPointer += pcmBytes / 2; + p_msg->offset += (p_msg->len - 1) - sbc_frame_len; + p_msg->len = sbc_frame_len + 1; + } + + btc_a2d_data_cb_to_app((uint8_t *)pcmData, (2 * sizeof(pcmData) - availPcmBytes)); +} + +/******************************************************************************* + ** + ** Function btc_media_task_aa_rx_flush_req + ** + ** Description + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +BOOLEAN btc_media_task_aa_rx_flush_req(void) +{ + BT_HDR *p_buf; + + if (GKI_queue_is_empty(&(btc_media_cb.RxSbcQ)) == TRUE) { /* Que is already empty */ + return TRUE; + } + + if (NULL == (p_buf = GKI_getbuf(sizeof(BT_HDR)))) { + return FALSE; + } + + p_buf->event = BTC_MEDIA_FLUSH_AA_RX; + + fixed_queue_enqueue(btc_media_cmd_msg_queue, p_buf); + btc_media_ctrl_post(SIG_MEDIA_TASK_CMD_READY); + return TRUE; +} + +/******************************************************************************* + ** + ** Function btc_media_task_aa_rx_flush + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btc_media_task_aa_rx_flush(void) +{ + /* Flush all enqueued GKI SBC buffers (encoded) */ + APPL_TRACE_DEBUG("btc_media_task_aa_rx_flush"); + + btc_media_flush_q(&(btc_media_cb.RxSbcQ)); +} + +int btc_a2dp_get_track_frequency(UINT8 frequency) +{ + int freq = 48000; + switch (frequency) { + case A2D_SBC_IE_SAMP_FREQ_16: + freq = 16000; + break; + case A2D_SBC_IE_SAMP_FREQ_32: + freq = 32000; + break; + case A2D_SBC_IE_SAMP_FREQ_44: + freq = 44100; + break; + case A2D_SBC_IE_SAMP_FREQ_48: + freq = 48000; + break; + } + return freq; +} + +int btc_a2dp_get_track_channel_count(UINT8 channeltype) +{ + int count = 1; + switch (channeltype) { + case A2D_SBC_IE_CH_MD_MONO: + count = 1; + break; + case A2D_SBC_IE_CH_MD_DUAL: + case A2D_SBC_IE_CH_MD_STEREO: + case A2D_SBC_IE_CH_MD_JOINT: + count = 2; + break; + } + return count; +} + +void btc_a2dp_set_peer_sep(UINT8 sep) +{ + btc_media_cb.peer_sep = sep; +} + +static void btc_media_task_aa_handle_clear_track (void) +{ + APPL_TRACE_DEBUG("btc_media_task_aa_handle_clear_track"); +} + +/******************************************************************************* + ** + ** Function btc_media_task_aa_handle_decoder_reset + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +static void btc_media_task_aa_handle_decoder_reset(BT_HDR *p_msg) +{ + tBTC_MEDIA_SINK_CFG_UPDATE *p_buf = (tBTC_MEDIA_SINK_CFG_UPDATE *) p_msg; + tA2D_STATUS a2d_status; + tA2D_SBC_CIE sbc_cie; + OI_STATUS status; + UINT32 freq_multiple = 48 * 20; /* frequency multiple for 20ms of data , initialize with 48K*/ + UINT32 num_blocks = 16; + UINT32 num_subbands = 8; + + APPL_TRACE_EVENT("btc_media_task_aa_handle_decoder_reset p_codec_info[%x:%x:%x:%x:%x:%x]\n", + p_buf->codec_info[1], p_buf->codec_info[2], p_buf->codec_info[3], + p_buf->codec_info[4], p_buf->codec_info[5], p_buf->codec_info[6]); + + a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_buf->codec_info, FALSE); + if (a2d_status != A2D_SUCCESS) { + APPL_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status); + return; + } + + btc_media_cb.sample_rate = btc_a2dp_get_track_frequency(sbc_cie.samp_freq); + btc_media_cb.channel_count = btc_a2dp_get_track_channel_count(sbc_cie.ch_mode); + + btc_media_cb.rx_flush = FALSE; + APPL_TRACE_EVENT("Reset to sink role"); + status = OI_CODEC_SBC_DecoderReset(&context, contextData, sizeof(contextData), 2, 2, FALSE); + if (!OI_SUCCESS(status)) { + APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status); + } + + btc_media_cb.data_channel_open = TRUE; + + switch (sbc_cie.samp_freq) { + case A2D_SBC_IE_SAMP_FREQ_16: + APPL_TRACE_DEBUG("\tsamp_freq:%d (16000)\n", sbc_cie.samp_freq); + freq_multiple = 16 * 20; + break; + case A2D_SBC_IE_SAMP_FREQ_32: + APPL_TRACE_DEBUG("\tsamp_freq:%d (32000)\n", sbc_cie.samp_freq); + freq_multiple = 32 * 20; + break; + case A2D_SBC_IE_SAMP_FREQ_44: + APPL_TRACE_DEBUG("\tsamp_freq:%d (44100)\n", sbc_cie.samp_freq); + freq_multiple = 441 * 2; + break; + case A2D_SBC_IE_SAMP_FREQ_48: + APPL_TRACE_DEBUG("\tsamp_freq:%d (48000)\n", sbc_cie.samp_freq); + freq_multiple = 48 * 20; + break; + default: + APPL_TRACE_DEBUG(" Unknown Frequency "); + break; + } + + switch (sbc_cie.ch_mode) { + case A2D_SBC_IE_CH_MD_MONO: + APPL_TRACE_DEBUG("\tch_mode:%d (Mono)\n", sbc_cie.ch_mode); + break; + case A2D_SBC_IE_CH_MD_DUAL: + APPL_TRACE_DEBUG("\tch_mode:%d (DUAL)\n", sbc_cie.ch_mode); + break; + case A2D_SBC_IE_CH_MD_STEREO: + APPL_TRACE_DEBUG("\tch_mode:%d (STEREO)\n", sbc_cie.ch_mode); + break; + case A2D_SBC_IE_CH_MD_JOINT: + APPL_TRACE_DEBUG("\tch_mode:%d (JOINT)\n", sbc_cie.ch_mode); + break; + default: + APPL_TRACE_DEBUG(" Unknown Mode "); + break; + } + + switch (sbc_cie.block_len) { + case A2D_SBC_IE_BLOCKS_4: + APPL_TRACE_DEBUG("\tblock_len:%d (4)\n", sbc_cie.block_len); + num_blocks = 4; + break; + case A2D_SBC_IE_BLOCKS_8: + APPL_TRACE_DEBUG("\tblock_len:%d (8)\n", sbc_cie.block_len); + num_blocks = 8; + break; + case A2D_SBC_IE_BLOCKS_12: + APPL_TRACE_DEBUG("\tblock_len:%d (12)\n", sbc_cie.block_len); + num_blocks = 12; + break; + case A2D_SBC_IE_BLOCKS_16: + APPL_TRACE_DEBUG("\tblock_len:%d (16)\n", sbc_cie.block_len); + num_blocks = 16; + break; + default: + APPL_TRACE_DEBUG(" Unknown BlockLen "); + break; + } + + switch (sbc_cie.num_subbands) { + case A2D_SBC_IE_SUBBAND_4: + APPL_TRACE_DEBUG("\tnum_subbands:%d (4)\n", sbc_cie.num_subbands); + num_subbands = 4; + break; + case A2D_SBC_IE_SUBBAND_8: + APPL_TRACE_DEBUG("\tnum_subbands:%d (8)\n", sbc_cie.num_subbands); + num_subbands = 8; + break; + default: + APPL_TRACE_DEBUG(" Unknown SubBands "); + break; + } + + switch (sbc_cie.alloc_mthd) { + case A2D_SBC_IE_ALLOC_MD_S: + APPL_TRACE_DEBUG("\talloc_mthd:%d (SNR)\n", sbc_cie.alloc_mthd); + break; + case A2D_SBC_IE_ALLOC_MD_L: + APPL_TRACE_DEBUG("\talloc_mthd:%d (Loudness)\n", sbc_cie.alloc_mthd); + break; + default: + APPL_TRACE_DEBUG(" Unknown Allocation Method"); + break; + } + + APPL_TRACE_EVENT("\tBit pool Min:%d Max:%d\n", sbc_cie.min_bitpool, sbc_cie.max_bitpool); + + int frames_to_process = ((freq_multiple) / (num_blocks * num_subbands)) + 1; + APPL_TRACE_EVENT(" Frames to be processed in 20 ms %d\n", frames_to_process); +} + +/******************************************************************************* + ** + ** Function btc_media_sink_enque_buf + ** + ** Description This function is called by the av_co to fill A2DP Sink Queue + ** + ** + ** Returns size of the queue + *******************************************************************************/ +UINT8 btc_media_sink_enque_buf(BT_HDR *p_pkt) +{ + tBT_SBC_HDR *p_msg; + + if (btc_media_cb.rx_flush == TRUE) { /* Flush enabled, do not enque*/ + return GKI_queue_length(&btc_media_cb.RxSbcQ); + } + + if (GKI_queue_length(&btc_media_cb.RxSbcQ) >= MAX_OUTPUT_A2DP_FRAME_QUEUE_SZ) { + APPL_TRACE_WARNING("Pkt dropped\n"); + } + + APPL_TRACE_DEBUG("btc_media_sink_enque_buf + "); + + /* allocate and Queue this buffer */ + if ((p_msg = (tBT_SBC_HDR *) GKI_getbuf(sizeof(tBT_SBC_HDR) + + p_pkt->offset + p_pkt->len)) != NULL) { + memcpy(p_msg, p_pkt, (sizeof(BT_HDR) + p_pkt->offset + p_pkt->len)); + p_msg->num_frames_to_be_processed = (*((UINT8 *)(p_msg + 1) + p_msg->offset)) & 0x0f; + APPL_TRACE_VERBOSE("btc_media_sink_enque_buf %d + \n", p_msg->num_frames_to_be_processed); + GKI_enqueue(&(btc_media_cb.RxSbcQ), p_msg); + btc_media_data_post(); + } else { + /* let caller deal with a failed allocation */ + APPL_TRACE_WARNING("btc_media_sink_enque_buf No Buffer left - "); + } + return GKI_queue_length(&btc_media_cb.RxSbcQ); +} + +/******************************************************************************* + ** + ** Function btc_media_aa_readbuf + ** + ** Description This function is called by the av_co to get the next buffer to send + ** + ** + ** Returns void + *******************************************************************************/ +BT_HDR *btc_media_aa_readbuf(void) +{ + return NULL; +} + +/******************************************************************************* + ** + ** Function dump_codec_info + ** + ** Description Decode and display codec_info (for debug) + ** + ** Returns void + ** + *******************************************************************************/ +void dump_codec_info(unsigned char *p_codec) +{ + tA2D_STATUS a2d_status; + tA2D_SBC_CIE sbc_cie; + + a2d_status = A2D_ParsSbcInfo(&sbc_cie, p_codec, FALSE); + if (a2d_status != A2D_SUCCESS) { + APPL_TRACE_ERROR("ERROR dump_codec_info A2D_ParsSbcInfo fail:%d\n", a2d_status); + return; + } + + APPL_TRACE_DEBUG("dump_codec_info"); + + if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_16) { + APPL_TRACE_DEBUG("\tsamp_freq:%d (16000)\n", sbc_cie.samp_freq); + } else if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_32) { + APPL_TRACE_DEBUG("\tsamp_freq:%d (32000)\n", sbc_cie.samp_freq); + } else if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_44) { + APPL_TRACE_DEBUG("\tsamp_freq:%d (44.100)\n", sbc_cie.samp_freq); + } else if (sbc_cie.samp_freq == A2D_SBC_IE_SAMP_FREQ_48) { + APPL_TRACE_DEBUG("\tsamp_freq:%d (48000)\n", sbc_cie.samp_freq); + } else { + APPL_TRACE_DEBUG("\tBAD samp_freq:%d\n", sbc_cie.samp_freq); + } + + if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_MONO) { + APPL_TRACE_DEBUG("\tch_mode:%d (Mono)\n", sbc_cie.ch_mode); + } else if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_DUAL) { + APPL_TRACE_DEBUG("\tch_mode:%d (Dual)\n", sbc_cie.ch_mode); + } else if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_STEREO) { + APPL_TRACE_DEBUG("\tch_mode:%d (Stereo)\n", sbc_cie.ch_mode); + } else if (sbc_cie.ch_mode == A2D_SBC_IE_CH_MD_JOINT) { + APPL_TRACE_DEBUG("\tch_mode:%d (Joint)\n", sbc_cie.ch_mode); + } else { + APPL_TRACE_DEBUG("\tBAD ch_mode:%d\n", sbc_cie.ch_mode); + } + + if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_4) { + APPL_TRACE_DEBUG("\tblock_len:%d (4)\n", sbc_cie.block_len); + } else if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_8) { + APPL_TRACE_DEBUG("\tblock_len:%d (8)\n", sbc_cie.block_len); + } else if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_12) { + APPL_TRACE_DEBUG("\tblock_len:%d (12)\n", sbc_cie.block_len); + } else if (sbc_cie.block_len == A2D_SBC_IE_BLOCKS_16) { + APPL_TRACE_DEBUG("\tblock_len:%d (16)\n", sbc_cie.block_len); + } else { + APPL_TRACE_DEBUG("\tBAD block_len:%d\n", sbc_cie.block_len); + } + + if (sbc_cie.num_subbands == A2D_SBC_IE_SUBBAND_4) { + APPL_TRACE_DEBUG("\tnum_subbands:%d (4)\n", sbc_cie.num_subbands); + } else if (sbc_cie.num_subbands == A2D_SBC_IE_SUBBAND_8) { + APPL_TRACE_DEBUG("\tnum_subbands:%d (8)\n", sbc_cie.num_subbands); + } else { + APPL_TRACE_DEBUG("\tBAD num_subbands:%d\n", sbc_cie.num_subbands); + } + + if (sbc_cie.alloc_mthd == A2D_SBC_IE_ALLOC_MD_S) { + APPL_TRACE_DEBUG("\talloc_mthd:%d (SNR)\n", sbc_cie.alloc_mthd); + } else if (sbc_cie.alloc_mthd == A2D_SBC_IE_ALLOC_MD_L) { + APPL_TRACE_DEBUG("\talloc_mthd:%d (Loundess)\n", sbc_cie.alloc_mthd); + } else { + APPL_TRACE_DEBUG("\tBAD alloc_mthd:%d\n", sbc_cie.alloc_mthd); + } + + APPL_TRACE_DEBUG("\tBit pool Min:%d Max:%d\n", sbc_cie.min_bitpool, sbc_cie.max_bitpool); + +} + +#endif /* #if BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h b/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h new file mode 100644 index 0000000000..43a83002e4 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/a2dp/include/btc_av_co.h @@ -0,0 +1,169 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BTC_AV_CO_H__ +#define __BTC_AV_CO_H__ + +#include "btc_media.h" + +/******************************************************************************* +** Constants & Macros +********************************************************************************/ + +enum { + BTC_SV_AV_AA_SBC_INDEX = 0, + BTC_SV_AV_AA_SBC_SINK_INDEX, + BTC_SV_AV_AA_SEP_INDEX /* Last index */ +}; + + +/******************************************************************************* +** Functions +********************************************************************************/ + +/******************************************************************************* + ** + ** Function bta_av_co_cp_is_active + ** + ** Description Get the current configuration of content protection + ** + ** Returns TRUE if the current streaming has CP, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_cp_is_active(void); + +/******************************************************************************* + ** + ** Function bta_av_co_cp_get_flag + ** + ** Description Get content protection flag + ** BTA_AV_CP_SCMS_COPY_NEVER + ** BTA_AV_CP_SCMS_COPY_ONCE + ** BTA_AV_CP_SCMS_COPY_FREE + ** + ** Returns The current flag value + ** + *******************************************************************************/ +UINT8 bta_av_co_cp_get_flag(void); + +/******************************************************************************* + ** + ** Function bta_av_co_cp_set_flag + ** + ** Description Set content protection flag + ** BTA_AV_CP_SCMS_COPY_NEVER + ** BTA_AV_CP_SCMS_COPY_ONCE + ** BTA_AV_CP_SCMS_COPY_FREE + ** + ** Returns TRUE if setting the SCMS flag is supported else FALSE + ** + *******************************************************************************/ +BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag); + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_reset + ** + ** Description Reset the current codec configuration + ** + ** Returns void + ** + *******************************************************************************/ +void bta_av_co_audio_codec_reset(void); + +/******************************************************************************* + ** + ** Function bta_av_co_audio_codec_supported + ** + ** Description Check if all opened connections are compatible with a codec + ** configuration + ** + ** Returns TRUE if all opened devices support this codec, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_codec_supported(tBTC_STATUS *p_status); + +/******************************************************************************* + ** + ** Function bta_av_co_audio_set_codec + ** + ** Description Set the current codec configuration from the feeding type. + ** This function is starting to modify the configuration, it + ** should be protected. + ** + ** Returns TRUE if successful, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_set_codec(const tBTC_AV_MEDIA_FEEDINGS *p_feeding, tBTC_STATUS *p_status); + +/******************************************************************************* + ** + ** Function bta_av_co_audio_get_sbc_config + ** + ** Description Retrieves the SBC codec configuration. If the codec in use + ** is not SBC, return the default SBC codec configuration. + ** + ** Returns TRUE if codec is SBC, FALSE otherwise + ** + *******************************************************************************/ +BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu); + +/******************************************************************************* + ** + ** Function bta_av_co_audio_discard_config + ** + ** Description Discard the codec configuration of a connection + ** + ** Returns Nothing + ** + *******************************************************************************/ +void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl); + +/******************************************************************************* + ** + ** Function bta_av_co_init + ** + ** Description Initialization + ** + ** Returns Nothing + ** + *******************************************************************************/ +void bta_av_co_init(void); + + +/******************************************************************************* + ** + ** Function bta_av_co_peer_cp_supported + ** + ** Description Checks if the peer supports CP + ** + ** Returns TRUE if the peer supports CP + ** + *******************************************************************************/ +BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl); + +/******************************************************************************* + ** + ** Function bta_av_co_get_remote_bitpool_pref + ** + ** Description Check if remote side did a setconfig within the limits + ** of our exported bitpool range. If set we will set the + ** remote preference. + ** + ** Returns TRUE if config set, FALSE otherwize + ** + *******************************************************************************/ +BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max); + +#endif diff --git a/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c new file mode 100644 index 0000000000..083cb876bb --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/avrc/btc_avrc.c @@ -0,0 +1,443 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + +/***************************************************************************** + * + * Filename: btc_avrc.c + * + * Description: Bluetooth AVRC implementation + * + *****************************************************************************/ +#include "bt_target.h" +#include +#include "bta_api.h" +#include "bta_av_api.h" +#include "avrc_defs.h" +#include "gki.h" +#include "btc_common.h" +#include "btc_util.h" +#include "btc_av.h" +#include "btc_avrc.h" +#include "btc_manage.h" +#include "esp_avrc_api.h" +#if BTC_AV_INCLUDED + +/***************************************************************************** +** Constants & Macros +******************************************************************************/ +/* for AVRC 1.4 need to change this */ +#define MAX_RC_NOTIFICATIONS AVRC_EVT_APP_SETTING_CHANGE + +#define MAX_VOLUME 128 +#define MAX_LABEL 16 +#define MAX_TRANSACTIONS_PER_SESSION 16 +#define MAX_CMD_QUEUE_LEN 8 + +#define CHECK_ESP_RC_CONNECTED do { \ + LOG_DEBUG("## %s ##", __FUNCTION__); \ + if (btc_rc_vb.rc_connected == FALSE) { \ + LOG_WARN("Function %s() called when RC is not connected", __FUNCTION__); \ + return ESP_ERR_INVALID_STATE; \ + } \ + } while (0) + +/***************************************************************************** +** Local type definitions +******************************************************************************/ +typedef struct { + UINT8 bNotify; + UINT8 label; +} btc_rc_reg_notifications_t; + +typedef struct { + UINT8 label; + UINT8 ctype; + BOOLEAN is_rsp_pending; +} btc_rc_cmd_ctxt_t; + +/* TODO : Merge btc_rc_reg_notifications_t and btc_rc_cmd_ctxt_t to a single struct */ +typedef struct { + BOOLEAN rc_connected; + UINT8 rc_handle; + tBTA_AV_FEAT rc_features; + BD_ADDR rc_addr; + UINT16 rc_pending_play; + btc_rc_cmd_ctxt_t rc_pdu_info[MAX_CMD_QUEUE_LEN]; + btc_rc_reg_notifications_t rc_notif[MAX_RC_NOTIFICATIONS]; + unsigned int rc_volume; + uint8_t rc_vol_label; +} btc_rc_cb_t; + +typedef struct { + BOOLEAN in_use; + UINT8 lbl; + UINT8 handle; +} rc_transaction_t; + +typedef struct { + pthread_mutex_t lbllock; + rc_transaction_t transaction[MAX_TRANSACTIONS_PER_SESSION]; +} rc_device_t; + +rc_device_t device; + +static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open); +static void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close); +static void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp); + +/***************************************************************************** +** Static variables +******************************************************************************/ +static btc_rc_cb_t btc_rc_vb; + +/***************************************************************************** +** Externs +******************************************************************************/ +/***************************************************************************** +** Static functions +******************************************************************************/ +static inline void btc_avrc_ct_cb_to_app(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param) +{ + esp_avrc_ct_cb_t btc_avrc_cb = (esp_avrc_ct_cb_t)btc_profile_cb_get(BTC_PID_AVRC); + if (btc_avrc_cb) { + btc_avrc_cb(event, param); + } +} + +static void handle_rc_features(void) +{ + btrc_remote_features_t rc_features = BTRC_FEAT_NONE; + bt_bdaddr_t rc_addr; + bdcpy(rc_addr.address, btc_rc_vb.rc_addr); + + // TODO(eisenbach): If devices need to be blacklisted for absolute + // volume, it should be added to device/include/interop_database.h + // For now, everything goes... If blacklisting is necessary, exclude + // the following bit here: + // btc_rc_vb.rc_features &= ~BTA_AV_FEAT_ADV_CTRL; + + if (btc_rc_vb.rc_features & BTA_AV_FEAT_BROWSE) { + rc_features |= BTRC_FEAT_BROWSE; + } + + if ( (btc_rc_vb.rc_features & BTA_AV_FEAT_ADV_CTRL) && + (btc_rc_vb.rc_features & BTA_AV_FEAT_RCTG)) { + rc_features |= BTRC_FEAT_ABSOLUTE_VOLUME; + } + + if (btc_rc_vb.rc_features & BTA_AV_FEAT_METADATA) { + rc_features |= BTRC_FEAT_METADATA; + } + + LOG_DEBUG("%s: rc_features=0x%x", __FUNCTION__, rc_features); +} + + +/*************************************************************************** + * Function handle_rc_connect + * + * - Argument: tBTA_AV_RC_OPEN RC open data structure + * + * - Description: RC connection event handler + * + ***************************************************************************/ +static void handle_rc_connect (tBTA_AV_RC_OPEN *p_rc_open) +{ + LOG_DEBUG("%s: rc_handle: %d", __FUNCTION__, p_rc_open->rc_handle); +#if (AVRC_CTLR_INCLUDED == TRUE) + bt_bdaddr_t rc_addr; +#endif + + if (p_rc_open->status == BTA_AV_SUCCESS) { + //check if already some RC is connected + if (btc_rc_vb.rc_connected) { + LOG_ERROR("Got RC OPEN in connected state, Connected RC: %d \ + and Current RC: %d", btc_rc_vb.rc_handle, p_rc_open->rc_handle ); + if ((btc_rc_vb.rc_handle != p_rc_open->rc_handle) + && (bdcmp(btc_rc_vb.rc_addr, p_rc_open->peer_addr))) { + LOG_DEBUG("Got RC connected for some other handle"); + BTA_AvCloseRc(p_rc_open->rc_handle); + return; + } + } + memcpy(btc_rc_vb.rc_addr, p_rc_open->peer_addr, sizeof(BD_ADDR)); + btc_rc_vb.rc_features = p_rc_open->peer_features; + btc_rc_vb.rc_vol_label = MAX_LABEL; + btc_rc_vb.rc_volume = MAX_VOLUME; + + btc_rc_vb.rc_connected = TRUE; + btc_rc_vb.rc_handle = p_rc_open->rc_handle; + + /* on locally initiated connection we will get remote features as part of connect */ + if (btc_rc_vb.rc_features != 0) { + handle_rc_features(); + } +#if (AVRC_CTLR_INCLUDED == TRUE) + bdcpy(rc_addr.address, btc_rc_vb.rc_addr); + /* report connection state if device is AVRCP target */ + if (btc_rc_vb.rc_features & BTA_AV_FEAT_RCTG) { + esp_avrc_ct_cb_param_t param; + memset(¶m, 0, sizeof(esp_avrc_ct_cb_param_t)); + param.conn_stat.connected = true; + param.conn_stat.feat_mask = btc_rc_vb.rc_features; + memcpy(param.conn_stat.remote_bda, &rc_addr, sizeof(esp_bd_addr_t)); + btc_avrc_ct_cb_to_app(ESP_AVRC_CT_CONNECTION_STATE_EVT, ¶m); + } +#endif + } else { + LOG_ERROR("%s Connect failed with error code: %d", + __FUNCTION__, p_rc_open->status); + btc_rc_vb.rc_connected = FALSE; + } +} + +/*************************************************************************** + * Function handle_rc_disconnect + * + * - Argument: tBTA_AV_RC_CLOSE RC close data structure + * + * - Description: RC disconnection event handler + * + ***************************************************************************/ +static void handle_rc_disconnect (tBTA_AV_RC_CLOSE *p_rc_close) +{ +#if (AVRC_CTLR_INCLUDED == TRUE) + bt_bdaddr_t rc_addr; + tBTA_AV_FEAT features; +#endif + LOG_DEBUG("%s: rc_handle: %d", __FUNCTION__, p_rc_close->rc_handle); + if ((p_rc_close->rc_handle != btc_rc_vb.rc_handle) + && (bdcmp(btc_rc_vb.rc_addr, p_rc_close->peer_addr))) { + LOG_ERROR("Got disconnect of unknown device"); + return; + } + + btc_rc_vb.rc_handle = 0; + btc_rc_vb.rc_connected = FALSE; + memset(btc_rc_vb.rc_addr, 0, sizeof(BD_ADDR)); + memset(btc_rc_vb.rc_notif, 0, sizeof(btc_rc_vb.rc_notif)); +#if (AVRC_CTLR_INCLUDED == TRUE) + features = btc_rc_vb.rc_features; +#endif + btc_rc_vb.rc_features = 0; + btc_rc_vb.rc_vol_label = MAX_LABEL; + btc_rc_vb.rc_volume = MAX_VOLUME; +#if (AVRC_CTLR_INCLUDED == TRUE) + bdcpy(rc_addr.address, btc_rc_vb.rc_addr); +#endif + memset(btc_rc_vb.rc_addr, 0, sizeof(BD_ADDR)); +#if (AVRC_CTLR_INCLUDED == TRUE) + /* report connection state if device is AVRCP target */ + if (features & BTA_AV_FEAT_RCTG) { + esp_avrc_ct_cb_param_t param; + memset(¶m, 0, sizeof(esp_avrc_ct_cb_param_t)); + param.conn_stat.connected = false; + memcpy(param.conn_stat.remote_bda, &rc_addr, sizeof(esp_bd_addr_t)); + btc_avrc_ct_cb_to_app(ESP_AVRC_CT_CONNECTION_STATE_EVT, ¶m); + } +#endif +} + +/*************************************************************************** + * Function handle_rc_passthrough_rsp + * + * - Argument: tBTA_AV_REMOTE_RSP passthrough command response + * + * - Description: Remote control passthrough response handler + * + ***************************************************************************/ +static void handle_rc_passthrough_rsp ( tBTA_AV_REMOTE_RSP *p_remote_rsp) +{ +#if (AVRC_CTLR_INCLUDED == TRUE) + const char *status; + if (btc_rc_vb.rc_features & BTA_AV_FEAT_RCTG) { + int key_state; + if (p_remote_rsp->key_state == AVRC_STATE_RELEASE) { + status = "released"; + key_state = 1; + } else { + status = "pressed"; + key_state = 0; + } + + LOG_DEBUG("%s: rc_id=%d status=%s", __FUNCTION__, p_remote_rsp->rc_id, status); + + do { + esp_avrc_ct_cb_param_t param; + memset(¶m, 0, sizeof(esp_avrc_ct_cb_param_t)); + param.psth_rsp.tl = p_remote_rsp->label; + param.psth_rsp.key_code = p_remote_rsp->rc_id; + param.psth_rsp.key_state = key_state; + btc_avrc_ct_cb_to_app(ESP_AVRC_CT_PASSTHROUGH_RSP_EVT, ¶m); + } while (0); + } else { + LOG_ERROR("%s DUT does not support AVRCP controller role", __FUNCTION__); + } +#else + LOG_ERROR("%s AVRCP controller role is not enabled", __FUNCTION__); +#endif +} + + +/*************************************************************************** + ** + ** Function btc_rc_handler + ** + ** Description RC event handler + ** + ***************************************************************************/ +void btc_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data) +{ + LOG_DEBUG ("%s event:%s", __FUNCTION__, dump_rc_event(event)); + switch (event) { + case BTA_AV_RC_OPEN_EVT: { + LOG_DEBUG("Peer_features:%x", p_data->rc_open.peer_features); + handle_rc_connect( &(p_data->rc_open) ); + } break; + + case BTA_AV_RC_CLOSE_EVT: { + handle_rc_disconnect( &(p_data->rc_close) ); + } break; + +#if (AVRC_CTLR_INCLUDED == TRUE) + case BTA_AV_REMOTE_RSP_EVT: { + LOG_DEBUG("RSP: rc_id:0x%x key_state:%d", p_data->remote_rsp.rc_id, + p_data->remote_rsp.key_state); + handle_rc_passthrough_rsp( (&p_data->remote_rsp) ); + } + break; +#endif + case BTA_AV_RC_FEAT_EVT: { + LOG_DEBUG("Peer_features:%x", p_data->rc_feat.peer_features); + btc_rc_vb.rc_features = p_data->rc_feat.peer_features; + handle_rc_features(); + } + break; + + // below events are not handled for now + case BTA_AV_META_MSG_EVT: + case BTA_AV_REMOTE_CMD_EVT: + default: + LOG_DEBUG("Unhandled RC event : 0x%x", event); + } +} + +/*************************************************************************** + ** + ** Function btc_rc_get_connected_peer + ** + ** Description Fetches the connected headset's BD_ADDR if any + ** + ***************************************************************************/ +BOOLEAN btc_rc_get_connected_peer(BD_ADDR peer_addr) +{ + if (btc_rc_vb.rc_connected == TRUE) { + bdcpy(peer_addr, btc_rc_vb.rc_addr); + return TRUE; + } + return FALSE; +} + +/************************************************************************************ +** AVRCP API Functions +************************************************************************************/ + +/******************************************************************************* +** +** Function btc_avrc_ct_init +** +** Description Initializes the AVRC interface +** +** Returns esp_err_t +** +*******************************************************************************/ +static void btc_avrc_ct_init(void) +{ + LOG_DEBUG("## %s ##", __FUNCTION__); + + memset (&btc_rc_vb, 0, sizeof(btc_rc_vb)); + btc_rc_vb.rc_vol_label = MAX_LABEL; + btc_rc_vb.rc_volume = MAX_VOLUME; +} + + +/*************************************************************************** +** +** Function cleanup_ctrl +** +** Description Closes the AVRC Controller interface +** +** Returns void +** +***************************************************************************/ +static void btc_avrc_ct_deinit(void) +{ + LOG_INFO("## %s ##", __FUNCTION__); + + memset(&btc_rc_vb, 0, sizeof(btc_rc_cb_t)); + LOG_INFO("## %s ## completed", __FUNCTION__); +} + +static bt_status_t btc_avrc_ct_send_passthrough_cmd(uint8_t tl, uint8_t key_code, uint8_t key_state) +{ + tAVRC_STS status = BT_STATUS_UNSUPPORTED; + if (tl >= 16 || + key_state > ESP_AVRC_PT_CMD_STATE_RELEASED) { + return ESP_ERR_INVALID_ARG; + } +#if (AVRC_CTLR_INCLUDED == TRUE) + CHECK_ESP_RC_CONNECTED; + LOG_DEBUG("%s: key-code: %d, key-state: %d", __FUNCTION__, + key_code, key_state); + if (btc_rc_vb.rc_features & BTA_AV_FEAT_RCTG) { + BTA_AvRemoteCmd(btc_rc_vb.rc_handle, tl, + (tBTA_AV_RC)key_code, (tBTA_AV_STATE)key_state); + status = BT_STATUS_SUCCESS; + LOG_INFO("%s: succesfully sent passthrough command to BTA", __FUNCTION__); + } else { + status = BT_STATUS_FAIL; + LOG_DEBUG("%s: feature not supported", __FUNCTION__); + } +#else + LOG_DEBUG("%s: feature not enabled", __FUNCTION__); +#endif + + return status; +} + +void btc_avrc_call_handler(btc_msg_t *msg) +{ + btc_avrc_args_t *arg = (btc_avrc_args_t *)(msg->arg); + switch (msg->act) { + case BTC_AVRC_CTRL_API_INIT_EVT: { + btc_avrc_ct_init(); + // todo: callback to application + break; + } + case BTC_AVRC_CTRL_API_DEINIT_EVT: { + btc_avrc_ct_deinit(); + // todo: callback to application + break; + } + case BTC_AVRC_CTRL_API_SND_PTCMD_EVT: { + btc_avrc_ct_send_passthrough_cmd(arg->pt_cmd.tl, arg->pt_cmd.key_code, arg->pt_cmd.key_state); + // todo: callback to application + break; + } + default: + LOG_WARN("%s : unhandled event: %d\n", __FUNCTION__, msg->act); + } +} + +#endif /* #if BTC_AV_INCLUDED */ diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 18fd7eb3da..09f3254471 100644 --- a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -814,9 +814,6 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) case BTC_GAP_BLE_ACT_CONFIG_LOCAL_PRIVACY: btc_ble_config_local_privacy(arg->cfg_local_privacy.privacy_enable); break; - case BTC_GAP_BLE_ACT_SET_DEV_NAME: - BTA_DmSetDeviceName(arg->set_dev_name.device_name); - break; case BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW: btc_ble_set_adv_data_raw(arg->cfg_adv_data_raw.raw_adv, arg->cfg_adv_data_raw.raw_adv_len, diff --git a/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c new file mode 100644 index 0000000000..07737b7d33 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/gap/btc_gap_bt.c @@ -0,0 +1,87 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "esp_gap_bt_api.h" +#include "btc_gap_bt.h" +#include "bta_api.h" +#include "bt_trace.h" +#include +#include "bt_target.h" + +#if BTC_GAP_BT_INCLUDED +void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + switch (msg->act) { + default: + // LOG_ERROR("Unhandled deep copy %d\n", msg->act); + break; + } +} + +static void btc_gap_bt_arg_deep_free(btc_msg_t *msg) +{ + LOG_DEBUG("%s \n", __func__); + switch (msg->act) { + default: + // LOG_DEBUG("Unhandled deep free %d\n", msg->act); + break; + } +} + +static void btc_bt_set_scan_mode(esp_bt_scan_mode_t mode) +{ + tBTA_DM_DISC disc_mode; + tBTA_DM_CONN conn_mode; + + switch (mode) { + case ESP_BT_SCAN_MODE_NONE: + disc_mode = BTA_DM_NON_DISC; + conn_mode = BTA_DM_NON_CONN; + break; + + case ESP_BT_SCAN_MODE_CONNECTABLE: + disc_mode = BTA_DM_NON_DISC; + conn_mode = BTA_DM_CONN; + break; + + case ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE: + disc_mode = BTA_DM_GENERAL_DISC; + conn_mode = BTA_DM_CONN; + break; + + default: + LOG_WARN("invalid scan mode (0x%x)", mode); + return; + } + + BTA_DmSetVisibility(disc_mode, conn_mode, BTA_DM_IGNORE, BTA_DM_IGNORE); + return; +} + +void btc_gap_bt_call_handler(btc_msg_t *msg) +{ + btc_gap_bt_args_t *arg = (btc_gap_bt_args_t *)msg->arg; + LOG_DEBUG("%s act %d\n", __func__, msg->act); + switch (msg->act) { + case BTC_GAP_BT_ACT_SET_SCAN_MODE: { + btc_bt_set_scan_mode(arg->set_scan_mode.mode); + break; + } + default: + break; + } + btc_gap_bt_arg_deep_free(msg); +} + +#endif /* #if BTC_GAP_BT_INCLUDED */ diff --git a/components/bt/bluedroid/btc/profile/std/include/bt_sdp.h b/components/bt/bluedroid/btc/profile/std/include/bt_sdp.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_av.h b/components/bt/bluedroid/btc/profile/std/include/btc_av.h new file mode 100644 index 0000000000..92ab081499 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/include/btc_av.h @@ -0,0 +1,174 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + + +/******************************************************************************* + * + * Filename: btc_av.h + * + * Description: Main API header file for all BTC AV functions accessed + * from internal stack. + * + *******************************************************************************/ + +#ifndef __BTC_AV_H__ +#define __BTC_AV_H__ + +#include "esp_a2dp_api.h" +#include "btc_task.h" +#include "btc_common.h" +#include "btc_sm.h" +#include "bta_av_api.h" + + +/******************************************************************************* +** Type definitions for callback functions +********************************************************************************/ + +typedef enum { + BTC_AV_CONNECT_REQ_EVT = BTA_AV_MAX_EVT, + BTC_AV_DISCONNECT_REQ_EVT, + BTC_AV_START_STREAM_REQ_EVT, + BTC_AV_STOP_STREAM_REQ_EVT, + BTC_AV_SUSPEND_STREAM_REQ_EVT, + BTC_AV_SINK_CONFIG_REQ_EVT, +} btc_av_sm_event_t; + +typedef enum { + BTC_AV_SINK_API_INIT_EVT = 0, + BTC_AV_SINK_API_DEINIT_EVT, + BTC_AV_SINK_API_CONNECT_EVT, + BTC_AV_SINK_API_DISCONNECT_EVT, + BTC_AV_SINK_API_REG_DATA_CB_EVT, +} btc_av_act_t; + +/* btc_av_args_t */ +typedef union { + // BTC_AV_SINK_CONFIG_REQ_EVT -- internal event + esp_a2d_mcc_t mcc; + // BTC_AV_SINK_API_CONNECT_EVT + bt_bdaddr_t connect; + // BTC_AV_SINK_API_REG_DATA_CB_EVT + esp_a2d_data_cb_t data_cb; +} btc_av_args_t; + +/******************************************************************************* +** BTC AV API +********************************************************************************/ + +void btc_a2dp_call_handler(btc_msg_t *msg); + +void btc_a2dp_cb_handler(btc_msg_t *msg); + +void btc_a2dp_sink_reg_data_cb(esp_a2d_data_cb_t callback); +/******************************************************************************* +** +** Function btc_av_get_sm_handle +** +** Description Fetches current av SM handle +** +** Returns None +** +*******************************************************************************/ + +btc_sm_handle_t btc_av_get_sm_handle(void); + +/******************************************************************************* +** +** Function btc_av_stream_ready +** +** Description Checks whether AV is ready for starting a stream +** +** Returns None +** +*******************************************************************************/ + +BOOLEAN btc_av_stream_ready(void); + +/******************************************************************************* +** +** Function btc_av_stream_started_ready +** +** Description Checks whether AV ready for media start in streaming state +** +** Returns None +** +*******************************************************************************/ + +BOOLEAN btc_av_stream_started_ready(void); + +/******************************************************************************* +** +** Function btc_dispatch_sm_event +** +** Description Send event to AV statemachine +** +** Returns None +** +*******************************************************************************/ + +/* used to pass events to AV statemachine from other tasks */ +void btc_dispatch_sm_event(btc_av_sm_event_t event, void *p_data, int len); + +/******************************************************************************* +** +** Function btc_av_init +** +** Description Initializes btc AV if not already done +** +** Returns bt_status_t +** +*******************************************************************************/ + +bt_status_t btc_av_init(void); + +/******************************************************************************* +** +** Function btc_av_is_connected +** +** Description Checks if av has a connected sink +** +** Returns BOOLEAN +** +*******************************************************************************/ + +BOOLEAN btc_av_is_connected(void); + + +/******************************************************************************* +** +** Function btc_av_is_peer_edr +** +** Description Check if the connected a2dp device supports +** EDR or not. Only when connected this function +** will accurately provide a true capability of +** remote peer. If not connected it will always be false. +** +** Returns TRUE if remote device is capable of EDR +** +*******************************************************************************/ + +BOOLEAN btc_av_is_peer_edr(void); + +/****************************************************************************** +** +** Function btc_av_clear_remote_suspend_flag +** +** Description Clears remote suspended flag +** +** Returns Void +********************************************************************************/ +void btc_av_clear_remote_suspend_flag(void); + +#endif /* __BTC_AV_H__ */ diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_av_api.h b/components/bt/bluedroid/btc/profile/std/include/btc_av_api.h new file mode 100644 index 0000000000..dc773bb9e3 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/include/btc_av_api.h @@ -0,0 +1,201 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + + +/***************************************************************************** + ** + ** Name: btc_av_api.h + ** + ** Description: This is the public interface file for the advanced + ** audio/video streaming (AV) subsystem of BTC. + ** + *****************************************************************************/ + +#ifndef __BTC_AV_API_H__ +#define __BTC_AV_API_H__ + +#include "bt_target.h" +#include "bta_av_api.h" + +#include "btc_media.h" +#include "a2d_api.h" +#include "a2d_sbc.h" + + +/***************************************************************************** + ** Constants and data types + *****************************************************************************/ + +/* Codec type */ +#define BTC_AV_CODEC_NONE 0xFF +#define BTC_AV_CODEC_SBC A2D_MEDIA_CT_SBC /* SBC media codec type */ + +#define BTC_AV_CODEC_PCM 0x5 /* Raw PCM */ + +typedef UINT8 tBTC_AV_CODEC_ID; + +/* AV features masks */ +#define BTC_AV_FEAT_RCTG BTA_AV_FEAT_RCTG /* remote control target */ +#define BTC_AV_FEAT_RCCT BTA_AV_FEAT_RCCT /* remote control controller */ +#define BTC_AV_FEAT_METADATA BTA_AV_FEAT_METADATA /* remote control Metadata Transfer command/response */ + +typedef UINT16 tBTC_AV_FEAT; + +/* AV channel values */ +#define BTC_AV_CHNL_MSK BTA_AV_CHNL_MSK +#define BTC_AV_CHNL_AUDIO BTA_AV_CHNL_AUDIO /* audio channel */ +#define BTC_AV_CHNL_VIDEO BTA_AV_CHNL_VIDEO /* video channel */ +typedef UINT8 tBTC_AV_CHNL; + +typedef UINT8 tBTC_AV_HNDL; + +/* Operation id list for BTC_AvRemoteCmd */ +#define BTC_AV_ID_SELECT 0x00 /* select */ +#define BTC_AV_ID_UP 0x01 /* up */ +#define BTC_AV_ID_DOWN 0x02 /* down */ +#define BTC_AV_ID_LEFT 0x03 /* left */ +#define BTC_AV_ID_RIGHT 0x04 /* right */ +#define BTC_AV_ID_RIGHT_UP 0x05 /* right-up */ +#define BTC_AV_ID_RIGHT_DOWN 0x06 /* right-down */ +#define BTC_AV_ID_LEFT_UP 0x07 /* left-up */ +#define BTC_AV_ID_LEFT_DOWN 0x08 /* left-down */ +#define BTC_AV_ID_ROOT_MENU 0x09 /* root menu */ +#define BTC_AV_ID_SETUP_MENU 0x0A /* setup menu */ +#define BTC_AV_ID_CONT_MENU 0x0B /* contents menu */ +#define BTC_AV_ID_FAV_MENU 0x0C /* favorite menu */ +#define BTC_AV_ID_EXIT 0x0D /* exit */ +#define BTC_AV_ID_0 0x20 /* 0 */ +#define BTC_AV_ID_1 0x21 /* 1 */ +#define BTC_AV_ID_2 0x22 /* 2 */ +#define BTC_AV_ID_3 0x23 /* 3 */ +#define BTC_AV_ID_4 0x24 /* 4 */ +#define BTC_AV_ID_5 0x25 /* 5 */ +#define BTC_AV_ID_6 0x26 /* 6 */ +#define BTC_AV_ID_7 0x27 /* 7 */ +#define BTC_AV_ID_8 0x28 /* 8 */ +#define BTC_AV_ID_9 0x29 /* 9 */ +#define BTC_AV_ID_DOT 0x2A /* dot */ +#define BTC_AV_ID_ENTER 0x2B /* enter */ +#define BTC_AV_ID_CLEAR 0x2C /* clear */ +#define BTC_AV_ID_CHAN_UP 0x30 /* channel up */ +#define BTC_AV_ID_CHAN_DOWN 0x31 /* channel down */ +#define BTC_AV_ID_PREV_CHAN 0x32 /* previous channel */ +#define BTC_AV_ID_SOUND_SEL 0x33 /* sound select */ +#define BTC_AV_ID_INPUT_SEL 0x34 /* input select */ +#define BTC_AV_ID_DISP_INFO 0x35 /* display information */ +#define BTC_AV_ID_HELP 0x36 /* help */ +#define BTC_AV_ID_PAGE_UP 0x37 /* page up */ +#define BTC_AV_ID_PAGE_DOWN 0x38 /* page down */ +#define BTC_AV_ID_POWER 0x40 /* power */ +#define BTC_AV_ID_VOL_UP 0x41 /* volume up */ +#define BTC_AV_ID_VOL_DOWN 0x42 /* volume down */ +#define BTC_AV_ID_MUTE 0x43 /* mute */ +#define BTC_AV_ID_PLAY 0x44 /* play */ +#define BTC_AV_ID_STOP 0x45 /* stop */ +#define BTC_AV_ID_PAUSE 0x46 /* pause */ +#define BTC_AV_ID_RECORD 0x47 /* record */ +#define BTC_AV_ID_REWIND 0x48 /* rewind */ +#define BTC_AV_ID_FAST_FOR 0x49 /* fast forward */ +#define BTC_AV_ID_EJECT 0x4A /* eject */ +#define BTC_AV_ID_FORWARD 0x4B /* forward */ +#define BTC_AV_ID_BACKWARD 0x4C /* backward */ +#define BTC_AV_ID_ANGLE 0x50 /* angle */ +#define BTC_AV_ID_SUBPICT 0x51 /* subpicture */ +#define BTC_AV_ID_F1 0x71 /* F1 */ +#define BTC_AV_ID_F2 0x72 /* F2 */ +#define BTC_AV_ID_F3 0x73 /* F3 */ +#define BTC_AV_ID_F4 0x74 /* F4 */ +#define BTC_AV_ID_F5 0x75 /* F5 */ +#define BTC_AV_ID_VENDOR 0x7E /* vendor unique */ +#define BTC_AV_KEYPRESSED_RELEASE 0x80 + +typedef UINT8 tBTC_AV_RC; + +/* State flag for pass through command */ +#define BTC_AV_STATE_PRESS 0 /* key pressed */ +#define BTC_AV_STATE_RELEASE 1 /* key released */ + +typedef UINT8 tBTC_AV_STATE; + +typedef UINT8 tBTC_AV_RC_HNDL; + +/* Command codes for BTC_AvVendorCmd */ +#define BTC_AV_CMD_CTRL 0 +#define BTC_AV_CMD_STATUS 1 +#define BTC_AV_CMD_SPEC_INQ 2 +#define BTC_AV_CMD_NOTIF 3 +#define BTC_AV_CMD_GEN_INQ 4 + +typedef UINT8 tBTC_AV_CMD; + +/* AV callback events */ +#define BTC_AV_OPEN_EVT 0 /* connection opened */ +#define BTC_AV_CLOSE_EVT 1 /* connection closed */ +#define BTC_AV_START_EVT 2 /* stream data transfer started */ +#define BTC_AV_STOP_EVT 3 /* stream data transfer stopped */ +#define BTC_AV_RC_OPEN_EVT 4 /* remote control channel open */ +#define BTC_AV_RC_CLOSE_EVT 5 /* remote control channel closed */ +#define BTC_AV_REMOTE_CMD_EVT 6 /* remote control command */ +#define BTC_AV_REMOTE_RSP_EVT 7 /* remote control response */ +#define BTC_AV_META_MSG_EVT 8 /* metadata messages */ + +typedef UINT8 tBTC_AV_EVT; + +#define BTC_AV_FEEDING_ASYNCHRONOUS 0 /* asynchronous feeding, use tx av timer */ +#define BTC_AV_FEEDING_SYNCHRONOUS 1 /* synchronous feeding, no av tx timer */ + +#define BTC_AV_MAX_SYNCHRONOUS_LATENCY 80 /* max latency in ms for BTC_AV_FEEDING_SYNCHRONOUS */ +#define BTC_AV_MIN_SYNCHRONOUS_LATENCY 4 /* min latency in ms for BTC_AV_FEEDING_SYNCHRONOUS */ + +typedef UINT8 tBTC_AV_FEEDING_MODE; + +#define BTC_AV_CHANNEL_MODE_MONO A2D_SBC_IE_CH_MD_MONO +#define BTC_AV_CHANNEL_MODE_STEREO A2D_SBC_IE_CH_MD_STEREO +#define BTC_AV_CHANNEL_MODE_JOINT A2D_SBC_IE_CH_MD_JOINT +#define BTC_AV_CHANNEL_MODE_DUAL A2D_SBC_IE_CH_MD_DUAL + +typedef UINT8 tBTC_AV_CHANNEL_MODE; + +/** + * Structure used to configure the AV codec capabilities/config + */ +typedef struct { + tBTC_AV_CODEC_ID id; /* Codec ID (in terms of BTC) */ + UINT8 info[AVDT_CODEC_SIZE]; /* Codec info (can be config or capabilities) */ +} tBTC_AV_CODEC_INFO; + +/** + * Structure used to configure the AV media feeding + */ +typedef struct { + UINT16 sampling_freq; /* 44100, 48000 etc */ + UINT16 num_channel; /* 1 for mono or 2 stereo */ + UINT8 bit_per_sample; /* Number of bits per sample (8, 16) */ +} tBTC_AV_MEDIA_FEED_CFG_PCM; + +typedef union { + tBTC_AV_MEDIA_FEED_CFG_PCM pcm; /* Raw PCM feeding format */ +} tBTC_AV_MEDIA_FEED_CFG; + +typedef struct { + tBTC_AV_CODEC_ID format; /* Media codec identifier */ + tBTC_AV_MEDIA_FEED_CFG cfg; /* Media codec configuration */ +} tBTC_AV_MEDIA_FEEDINGS; + + +#ifdef __cplusplus +} +#endif + +#endif /* __BTC_AV_API_H__ */ diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h new file mode 100644 index 0000000000..b9efb9db34 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/include/btc_avrc.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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 __BTC_AVRC_H__ +#define __BTC_AVRC_H__ + +#include +#include +#include "bt_defs.h" +#include "bt_types.h" +#include "bta_av_api.h" + +#ifndef BTC_AVRC_TGT_INCLUDED +#define BTC_AVRC_TGT_INCLUDED FALSE +#endif + +/* Macros */ +typedef enum { + BTRC_FEAT_NONE = 0x00, /* AVRCP 1.0 */ + BTRC_FEAT_METADATA = 0x01, /* AVRCP 1.3 */ + BTRC_FEAT_ABSOLUTE_VOLUME = 0x02, /* Supports TG role and volume sync */ + BTRC_FEAT_BROWSE = 0x04, /* AVRCP 1.4 and up, with Browsing support */ +} btrc_remote_features_t; + +typedef enum { + BTC_AVRC_CTRL_API_INIT_EVT = 0, + BTC_AVRC_CTRL_API_DEINIT_EVT, + BTC_AVRC_CTRL_API_SND_PTCMD_EVT +} btc_avrc_act_t; + +typedef struct { + uint8_t tl; /* transaction label */ + uint8_t key_code; + uint8_t key_state; +} pt_cmd_t; + +/* btc_avrc_args_t */ +typedef union { + // BTC_AVRC_CTRL_API_SND_PT_CMD_EVT + struct { + uint8_t tl; + uint8_t key_code; + uint8_t key_state; + } pt_cmd; +} btc_avrc_args_t; + +/** BT-RC Controller callback structure. */ +typedef void (* btrc_passthrough_rsp_callback) (int id, int key_state); + +typedef void (* btrc_connection_state_callback) (bool state, bt_bdaddr_t *bd_addr); + +void btc_rc_handler(tBTA_AV_EVT event, tBTA_AV *p_data); + +BOOLEAN btc_rc_get_connected_peer(BD_ADDR peer_addr); + +/******************************************************************************* +** BTC AVRC API +********************************************************************************/ +void btc_avrc_call_handler(btc_msg_t *msg); + +#endif /* __BTC_AVRC_H__ */ diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h b/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h index ea639bcde9..cc32eb76bc 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_gap_ble.h @@ -31,7 +31,6 @@ typedef enum { BTC_GAP_BLE_ACT_SET_PKT_DATA_LEN, BTC_GAP_BLE_ACT_SET_RAND_ADDRESS, BTC_GAP_BLE_ACT_CONFIG_LOCAL_PRIVACY, - BTC_GAP_BLE_ACT_SET_DEV_NAME, BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW, BTC_GAP_BLE_ACT_CFG_SCAN_RSP_DATA_RAW, } btc_gap_ble_act_t; @@ -73,11 +72,6 @@ typedef union { struct cfg_local_privacy_args { bool privacy_enable; } cfg_local_privacy; - //BTC_GAP_BLE_ACT_SET_DEV_NAME, - struct set_dev_name_args { -#define ESP_GAP_DEVICE_NAME_MAX (32) - char device_name[ESP_GAP_DEVICE_NAME_MAX + 1]; - } set_dev_name; //BTC_GAP_BLE_ACT_CFG_ADV_DATA_RAW, struct config_adv_data_raw_args { uint8_t *raw_adv; diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h b/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h index d6f2e5b535..d77a4b9f65 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_gap_bt.h @@ -15,8 +15,24 @@ #ifndef __BTC_GAP_BT_H__ #define __BTC_GAP_BT_H__ +#include "esp_bt_defs.h" +#include "esp_gap_bt_api.h" +#include "btc_task.h" +typedef enum { + BTC_GAP_BT_ACT_SET_SCAN_MODE = 0, +} btc_gap_bt_act_t; +/* btc_bt_gap_args_t */ +typedef union { + // BTC_BT_GAP_ACT_SET_SCAN_MODE, + struct set_bt_scan_mode_args { + esp_bt_scan_mode_t mode; + } set_scan_mode; +} btc_gap_bt_args_t; +void btc_gap_bt_call_handler(btc_msg_t *msg); -#define /* __BTC_GAP_BT_H__ */ +void btc_gap_bt_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); + +#endif /* __BTC_GAP_BT_H__ */ diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_media.h b/components/bt/bluedroid/btc/profile/std/include/btc_media.h new file mode 100644 index 0000000000..3ff0d1e108 --- /dev/null +++ b/components/bt/bluedroid/btc/profile/std/include/btc_media.h @@ -0,0 +1,267 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + +/******************************************************************************* + * + * Filename: btc_media.h + * + * Description: This is the audio module for the BTC system. + * + *******************************************************************************/ + +#ifndef __BTC_MEDIA_H__ +#define __BTC_MEDIA_H__ + +#include +#include "bta_api.h" +#include "gki.h" +#include "btc_av_api.h" + + +/******************************************************************************* + ** Constants + *******************************************************************************/ +#define BTC_SUCCESS (0) +/** + * AV (Audio Video source) Errors + */ +#define BTC_ERROR_SRV_AV_NOT_ENABLED 700 /* AV is not enabled */ +#define BTC_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED 701 /* Requested Feeding not supported */ +#define BTC_ERROR_SRV_AV_BUSY 702 /* Another operation ongoing */ +#define BTC_ERROR_SRV_AV_NOT_OPENED 703 /* No AV link opened */ +#define BTC_ERROR_SRV_AV_NOT_STARTED 704 /* AV is not started */ +#define BTC_ERROR_SRV_AV_CP_NOT_SUPPORTED 705 /* Content protection is not supported by all headsets */ + +/* Transcoding definition for TxTranscoding and RxTranscoding */ +#define BTC_MEDIA_TRSCD_OFF 0 +#define BTC_MEDIA_TRSCD_PCM_2_SBC 1 /* Tx */ + + +/******************************************************************************* + ** Data types + *******************************************************************************/ + +typedef int tBTC_STATUS; + +/* tBTC_MEDIA_INIT_AUDIO msg structure */ +typedef struct { + BT_HDR hdr; + UINT16 SamplingFreq; /* 16k, 32k, 44.1k or 48k*/ + UINT8 ChannelMode; /* mono, dual, stereo or joint stereo*/ + UINT8 NumOfSubBands; /* 4 or 8 */ + UINT8 NumOfBlocks; /* 4, 8, 12 or 16*/ + UINT8 AllocationMethod; /* loudness or SNR*/ + UINT16 MtuSize; /* peer mtu size */ +} tBTC_MEDIA_INIT_AUDIO; + +#if (BTA_AV_INCLUDED == TRUE) +/* tBTC_MEDIA_UPDATE_AUDIO msg structure */ +typedef struct { + BT_HDR hdr; + UINT16 MinMtuSize; /* Minimum peer mtu size */ + UINT8 MaxBitPool; /* Maximum peer bitpool */ + UINT8 MinBitPool; /* Minimum peer bitpool */ +} tBTC_MEDIA_UPDATE_AUDIO; + +/* tBTC_MEDIA_INIT_AUDIO_FEEDING msg structure */ +typedef struct { + BT_HDR hdr; + tBTC_AV_FEEDING_MODE feeding_mode; + tBTC_AV_MEDIA_FEEDINGS feeding; +} tBTC_MEDIA_INIT_AUDIO_FEEDING; + +typedef struct { + BT_HDR hdr; + UINT8 codec_info[AVDT_CODEC_SIZE]; +} tBTC_MEDIA_SINK_CFG_UPDATE; +#endif + +/******************************************************************************* + ** Public functions + *******************************************************************************/ + +/******************************************************************************* + ** + ** Function btc_av_task + ** + ** Description + ** + ** Returns void + ** + *******************************************************************************/ +extern void btc_media_task(void); + +/******************************************************************************* + ** + ** Function btc_media_task_enc_init_req + ** + ** Description Request to initialize the media task encoder + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern BOOLEAN btc_media_task_enc_init_req(tBTC_MEDIA_INIT_AUDIO *p_msg); + +/******************************************************************************* + ** + ** Function btc_media_task_enc_update_req + ** + ** Description Request to update the media task encoder + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +#if (BTA_AV_INCLUDED == TRUE) +extern BOOLEAN btc_media_task_enc_update_req(tBTC_MEDIA_UPDATE_AUDIO *p_msg); +#endif + +/******************************************************************************* + ** + ** Function btc_media_task_start_aa_req + ** + ** Description Request to start audio encoding task + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern BOOLEAN btc_media_task_start_aa_req(void); + +/******************************************************************************* + ** + ** Function btc_media_task_stop_aa_req + ** + ** Description Request to stop audio encoding task + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern BOOLEAN btc_media_task_stop_aa_req(void); + +/******************************************************************************* + ** + ** Function btc_media_task_aa_rx_flush_req + ** + ** Description Request to flush audio decoding pipe + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern BOOLEAN btc_media_task_aa_rx_flush_req(void); +/******************************************************************************* + ** + ** Function btc_media_task_aa_tx_flush_req + ** + ** Description Request to flush audio encoding pipe + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern BOOLEAN btc_media_task_aa_tx_flush_req(void); + +/******************************************************************************* + ** + ** Function btc_media_aa_readbuf + ** + ** Description Read an audio GKI buffer from the BTC media TX queue + ** + ** Returns pointer on a GKI aa buffer ready to send + ** + *******************************************************************************/ +extern BT_HDR *btc_media_aa_readbuf(void); + +/******************************************************************************* + ** + ** Function btc_media_sink_enque_buf + ** + ** Description This function is called by the av_co to fill A2DP Sink Queue + ** + ** + ** Returns size of the queue + *******************************************************************************/ +UINT8 btc_media_sink_enque_buf(BT_HDR *p_buf); + + + +/******************************************************************************* + ** + ** Function btc_media_aa_writebuf + ** + ** Description Enqueue a Advance Audio media GKI buffer to be processed by btc media task. + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern void btc_media_aa_writebuf(BT_HDR *pBuf, UINT32 timestamp, UINT16 seq_num); + +/******************************************************************************* + ** + ** Function btc_media_av_writebuf + ** + ** Description Enqueue a video media GKI buffer to be processed by btc media task. + ** + ** Returns TRUE is success + ** + *******************************************************************************/ +extern BOOLEAN btc_media_av_writebuf(UINT8 *p_media, UINT32 media_len, + UINT32 timestamp, UINT16 seq_num); + +#if (BTA_AV_INCLUDED == TRUE) +/******************************************************************************* + ** + ** Function btc_media_task_audio_feeding_init_req + ** + ** Description Request to initialize audio feeding + ** + ** Returns TRUE is success + ** + *******************************************************************************/ + +extern BOOLEAN btc_media_task_audio_feeding_init_req(tBTC_MEDIA_INIT_AUDIO_FEEDING *p_msg); +#endif + +/******************************************************************************* + ** + ** Function dump_codec_info + ** + ** Description Decode and display codec_info (for debug) + ** + ** Returns void + ** + *******************************************************************************/ +extern void dump_codec_info(unsigned char *p_codec); + +/** + * Local adaptation helper functions between btc and media task + */ + +bool btc_a2dp_start_media_task(void); +void btc_a2dp_stop_media_task(void); + +void btc_a2dp_on_init(void); +void btc_a2dp_setup_codec(void); +void btc_a2dp_on_idle(void); +BOOLEAN btc_a2dp_on_started(tBTA_AV_START *p_av, BOOLEAN pending_start); +void btc_a2dp_on_stop_req(void); +void btc_a2dp_on_stopped(tBTA_AV_SUSPEND *p_av); +void btc_a2dp_on_suspend(void); +void btc_a2dp_on_suspended(tBTA_AV_SUSPEND *p_av); +void btc_a2dp_set_rx_flush(BOOLEAN enable); +void btc_media_check_iop_exceptions(UINT8 *peer_bda); +void btc_reset_decoder(UINT8 *p_av); + +int btc_a2dp_get_track_frequency(UINT8 frequency); +int btc_a2dp_get_track_channel_count(UINT8 channeltype); +void btc_a2dp_set_peer_sep(UINT8 sep); + +#endif diff --git a/components/bt/bluedroid/btc/profile/std/sdp/btc_sdp.c b/components/bt/bluedroid/btc/profile/std/sdp/btc_sdp.c deleted file mode 100644 index 382f6dc021..0000000000 --- a/components/bt/bluedroid/btc/profile/std/sdp/btc_sdp.c +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 "esp_sdp_api.h" - - -esp_err_t esp_bt_sdp_enable(bt_sdp_cb_t *cback) -{ - tBTA_SDP_STATUS status = BTA_SdpEnable((tBTA_SDP_DM_CBACK *)cback); - - return (status == BTA_SDP_SUCCESS) ? ESP_OK : ESP_FAIL; -} - -esp_err_t esp_bt_sdp_search(esp_bd_addr_t bd_addr, esp_bt_uuid_t *uuid) -{ - tBTA_SDP_STATUS status = BTA_SdpSearch(bd_addr, (tSDP_UUID *)uuid); - return (status == BTA_SDP_SUCCESS) ? ESP_OK : ESP_FAIL; -} - -esp_err_t esp_bt_sdp_create_record_by_user(void *user_data) -{ - tBTA_SDP_STATUS status = BTA_SdpCreateRecordByUser(user_data); - return (status == BTA_SDP_SUCCESS) ? ESP_OK : ESP_FAIL; -} - -esp_err_t esp_bt_sdp_remove_record_by_user(void *user_data) -{ - tBTA_SDP_STATUS status = BTA_SdpRemoveRecordByUser(user_data); - return (status == BTA_SDP_SUCCESS) ? ESP_OK : ESP_FAIL; -} - - -/**********************************************************************************************/ -/**********************************************************************************************/ -/* API into SDP for local service database updates */ -/* these APIs are indended to be called in callback function in the context of stack task, - * to handle BT_SDP_CREATE_RECORD_USER_EVT and BT_SDP_REMOVE_RECORD_USER_EVT - */ -uint32_t esp_bt_sdp_create_record(void) -{ - return SDP_CreateRecord(); -} - -bool esp_bt_sdp_delete_record(uint32_t handle) -{ - return SDP_DeleteRecord(handle); -} - -int32_t esp_bt_sdp_read_record(uint32_t handle, uint8_t *data, int32_t *data_len) -{ - return SDP_ReadRecord(handle, data, data_len); -} - -bool esp_bt_sdp_add_attribute (uint32_t handle, uint16_t attr_id, - uint8_t attr_type, uint32_t attr_len, - uint8_t *p_val) -{ - return SDP_AddAttribute(handle, attr_id, attr_type, attr_len, p_val); -} - -bool esp_bt_sdp_add_sequence (uint32_t handle, uint16_t attr_id, - uint16_t num_elem, uint8_t type[], - uint8_t len[], uint8_t *p_val[]) -{ - return SDP_AddSequence(handle, attr_id, num_elem, type, len, p_val); -} - -bool esp_bt_sdp_add_uuid_sequence (uint32_t handle, uint16_t attr_id, - uint16_t num_uuids, uint16_t *p_uuids) -{ - return SDP_AddUuidSequence(handle, attr_id, num_uuids, p_uuids); -} - - -bool esp_bt_sdp_add_protocol_list (uint32_t handle, uint16_t num_elem, - sdp_proto_elem_t *p_elem_list) -{ - return SDP_AddProtocolList(handle, num_elem, (tSDP_PROTOCOL_ELEM *)p_elem_list); -} - -bool esp_bt_sdp_add_addition_protocol_lists(uint32_t handle, uint16_t num_elem, - sdp_proto_list_elem_t *p_proto_list) -{ - return SDP_AddAdditionProtoLists(handle, num_elem, (tSDP_PROTO_LIST_ELEM *)p_proto_list); -} - -bool esp_bt_sdp_add_profile_dscp_list (uint32_t handle, - uint16_t profile_uuid, - uint16_t version) -{ - return SDP_AddProfileDescriptorList(handle, profile_uuid, version); -} - -bool esp_bt_sdp_add_lang_base_attr_id_list(uint32_t handle, - uint16_t lang, uint16_t char_enc, - uint16_t base_id) -{ - return SDP_AddLanguageBaseAttrIDList(handle, lang, char_enc, base_id); -} - -bool esp_bt_sdp_add_service_class_id_list(uint32_t handle, - uint16_t num_services, - uint16_t *p_service_uuids) -{ - return SDP_AddServiceClassIdList(handle, num_services, p_service_uuids); -} - -bool esp_bt_sdp_delete_attribute(uint32_t handle, uint16_t attr_id) -{ - return SDP_DeleteAttribute(handle, attr_id); -} - -/**********************************************************************************************/ -/**********************************************************************************************/ diff --git a/components/bt/bluedroid/btc/profile/std/sdp/include/btc_sdp.h b/components/bt/bluedroid/btc/profile/std/sdp/include/btc_sdp.h deleted file mode 100644 index db7984b9b9..0000000000 --- a/components/bt/bluedroid/btc/profile/std/sdp/include/btc_sdp.h +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __ESP_SDP_API_H__ -#define __ESP_SDP_API_H__ - -#include -#include "esp_err.h" -#include "esp_bt_common.h" -#include "bta_sdp_api.h" -#include "bt_sdp.h" - -#define BT_SDP_STAT_SUCCESS BTA_SDP_SUCCESS -#define BT_SDP_STAT_FAILURE BTA_SDP_FAILURE -#define BT_SDP_STAT_BUSY BTA_SDP_BUSY - -#define BT_SDP_ENABLE_EVT BTA_SDP_ENABLE_EVT -#define BT_SDP_SEARCH_EVT BTA_SDP_SEARCH_EVT -#define BT_SDP_SEARCH_COMP_EVT BTA_SDP_SEARCH_COMP_EVT -#define BT_SDP_CREATE_RECORD_USER_EVT BTA_SDP_CREATE_RECORD_USER_EVT -#define BT_SDP_REMOVE_RECORD_USER_EVT BTA_SDP_REMOVE_RECORD_USER_EVT -#define BT_SDP_MAX_EVT BTA_SDP_MAX_EVT - -#define BT_SDP_MAX_RECORDS BTA_SDP_MAX_RECORDS - -typedef tBTA_SDP_STATUS bt_sdp_status_t; - -typedef tBTA_SDP_EVT bt_sdp_evt_t; - -typedef bluetooth_sdp_record bt_sdp_record_t; - -/* tBTA_SEARCH_COMP, bta_sdp_api.h */ -typedef struct { - bt_sdp_status_t status; - esp_bd_addr_t remote_addr; - esp_bt_uuid_t uuid; - int record_count; - bt_sdp_record_t records[BT_SDP_MAX_RECORDS]; -} bt_sdp_search_comp_t; - -/* tBTA_SDP, bta_sdp_api.h */ -typedef union { - bt_sdp_status_t status; - bt_sdp_search_comp_t sdp_search_comp; -} bt_sdp_t; - -typedef void (bt_sdp_cb_t)(bt_sdp_evt_t event, bt_sdp_t *p_data, void *user_data); - -esp_err_t esp_bt_sdp_enable(bt_sdp_cb_t *cback); - -esp_err_t esp_bt_sdp_search(esp_bd_addr_t bd_addr, esp_bt_uuid_t *uuid); - -esp_err_t esp_bt_sdp_create_record_by_user(void *user_data); - -esp_err_t esp_bt_sdp_remove_record_by_user(void *user_data); - - -/**********************************************************************************************/ -/**********************************************************************************************/ -/* API into SDP for local service database updates - * these APIs are indended to be called in callback function in the context of stack task, - * to handle BT_SDP_CREATE_RECORD_USER_EVT and BT_SDP_REMOVE_RECORD_USER_EVT - */ - -/* This structure is used to add protocol lists and find protocol elements */ -#define ESP_BT_SDP_MAX_PROTOCOL_PARAMS SDP_MAX_PROTOCOL_PARAMS // bt_target.h -typedef struct { - uint16_t protocol_uuid; - uint16_t num_params; - uint16_t params[ESP_BT_SDP_MAX_PROTOCOL_PARAMS]; -} sdp_proto_elem_t; // tSDP_PROTOCOL_ELEM, sdp_api.h - -#define ESP_BT_SDP_MAX_LIST_ELEMS SDP_MAX_LIST_ELEMS // sdp_api.h -typedef struct { - uint16_t num_elems; - sdp_proto_elem_t list_elem[ESP_BT_SDP_MAX_LIST_ELEMS]; -} sdp_proto_list_elem_t; // tSDP_PROTO_LIST_ELEM, sdp_api.h - - -uint32_t esp_bt_sdp_create_record(void); - -bool esp_bt_sdp_delete_record(uint32_t handle); - -int32_t esp_bt_sdp_read_record(uint32_t handle, uint8_t *data, int32_t *data_len); - -bool esp_bt_sdp_add_attribute (uint32_t handle, uint16_t attr_id, - uint8_t attr_type, uint32_t attr_len, - uint8_t *p_val); - -bool esp_bt_sdp_add_sequence (uint32_t handle, uint16_t attr_id, - uint16_t num_elem, uint8_t type[], - uint8_t len[], uint8_t *p_val[]); - -bool esp_bt_sdp_add_uuid_sequence (uint32_t handle, uint16_t attr_id, - uint16_t num_uuids, uint16_t *p_uuids); - - -bool esp_bt_sdp_add_protocol_list (uint32_t handle, uint16_t num_elem, - sdp_proto_elem_t *p_elem_list); - -bool esp_bt_sdp_add_addition_protocol_lists(uint32_t handle, uint16_t num_elem, - sdp_proto_list_elem_t *p_proto_list); - -bool esp_bt_sdp_add_profile_dscp_list (uint32_t handle, - uint16_t profile_uuid, - uint16_t version); - -bool esp_bt_sdp_add_lang_base_attr_id_list(uint32_t handle, - uint16_t lang, uint16_t char_enc, - uint16_t base_id); - -bool esp_bt_sdp_add_service_class_id_list(uint32_t handle, - uint16_t num_services, - uint16_t *p_service_uuids); - -bool esp_bt_sdp_delete_attribute(uint32_t handle, uint16_t attr_id); - -#endif /* __ESP_SDP_API_H__ */ diff --git a/components/bt/bluedroid/btcore/include/bdaddr.h b/components/bt/bluedroid/btcore/include/bdaddr.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_assert.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_assert.h new file mode 100644 index 0000000000..9649f660c1 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_assert.h @@ -0,0 +1,86 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_ASSERT_H +#define _OI_ASSERT_H +/** @file + This file provides macros and functions for compile-time and run-time assertions. + + When the OI_DEBUG preprocessor value is defined, the macro OI_ASSERT is compiled into + the program, providing for a runtime assertion failure check. + C_ASSERT is a macro that can be used to perform compile time checks. +*/ +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + + +/** \addtogroup Debugging Debugging APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef OI_DEBUG + +/** The macro OI_ASSERT takes a condition argument. If the asserted condition + does not evaluate to true, the OI_ASSERT macro calls the host-dependent function, + OI_AssertFail(), which reports the failure and generates a runtime error. +*/ +void OI_AssertFail(char *file, int line, char *reason); + + +#define OI_ASSERT(condition) \ + { if (!(condition)) OI_AssertFail(__FILE__, __LINE__, #condition); } + +#define OI_ASSERT_FAIL(msg) \ + { OI_AssertFail(__FILE__, __LINE__, msg); } + +#else + + +#define OI_ASSERT(condition) +#define OI_ASSERT_FAIL(msg) + +#endif + + +/** + C_ASSERT() can be used to perform many compile-time assertions: type sizes, field offsets, etc. + An assertion failure results in compile time error C2118: negative subscript. + Unfortunately, this elegant macro doesn't work with GCC, so it's all commented out + for now. Perhaps later..... +*/ + +#ifndef C_ASSERT +// #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +// #define C_ASSERT(e) +#endif + + +/*****************************************************************************/ +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* _OI_ASSERT_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_bitstream.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_bitstream.h new file mode 100644 index 0000000000..c6ce59b4ce --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_bitstream.h @@ -0,0 +1,123 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_BITSTREAM_H +#define _OI_BITSTREAM_H + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + + +/** +@file +Function prototypes and macro definitions for manipulating input and output +bitstreams. + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +#include "oi_codec_sbc_private.h" +#include "oi_stddefs.h" + +INLINE void OI_BITSTREAM_ReadInit(OI_BITSTREAM *bs, const OI_BYTE *buffer); + +INLINE void OI_BITSTREAM_WriteInit(OI_BITSTREAM *bs, OI_BYTE *buffer); + +INLINE OI_UINT32 OI_BITSTREAM_ReadUINT(OI_BITSTREAM *bs, OI_UINT bits); + +INLINE OI_UINT8 OI_BITSTREAM_ReadUINT4Aligned(OI_BITSTREAM *bs); + +INLINE OI_UINT8 OI_BITSTREAM_ReadUINT8Aligned(OI_BITSTREAM *bs); + +INLINE void OI_BITSTREAM_WriteUINT(OI_BITSTREAM *bs, + OI_UINT16 value, + OI_UINT bits); + +/* + * Use knowledge that the bitstream is aligned to optimize the write of a byte + */ +PRIVATE void OI_BITSTREAM_WriteUINT8Aligned(OI_BITSTREAM *bs, + OI_UINT8 datum); + +/* + * Use knowledge that the bitstream is aligned to optimize the write pair of nibbles + */ +PRIVATE void OI_BITSTREAM_Write2xUINT4Aligned(OI_BITSTREAM *bs, + OI_UINT8 datum1, + OI_UINT8 datum2); + +/** Internally the bitstream looks ahead in the stream. When + * OI_SBC_ReadScalefactors() goes to temporarily break the abstraction, it will + * need to know where the "logical" pointer is in the stream. + */ +#define OI_BITSTREAM_GetWritePtr(bs) ((bs)->ptr.w - 3) +#define OI_BITSTREAM_GetReadPtr(bs) ((bs)->ptr.r - 3) + +/** This is declared here as a macro because decoder.c breaks the bitsream + * encapsulation for efficiency reasons. + */ +#define OI_BITSTREAM_READUINT(result, bits, ptr, value, bitPtr) \ +do { \ + OI_ASSERT((bits) <= 16); \ + OI_ASSERT((bitPtr) < 16); \ + OI_ASSERT((bitPtr) >= 8); \ + \ + result = (value) << (bitPtr); \ + result >>= 32 - (bits); \ + \ + bitPtr += (bits); \ + while (bitPtr >= 16) { \ + value = ((value) << 8) | *ptr++; \ + bitPtr -= 8; \ + } \ + OI_ASSERT((bits == 0) || (result < (1u << (bits)))); \ +} while (0) + + +#define OI_BITSTREAM_WRITEUINT(ptr, value, bitPtr, datum, bits) \ +do {\ + bitPtr -= bits;\ + value |= datum << bitPtr;\ + \ + while (bitPtr <= 16) {\ + bitPtr += 8;\ + *ptr++ = (OI_UINT8)(value >> 24);\ + value <<= 8;\ + }\ +} while (0) + +#define OI_BITSTREAM_WRITEFLUSH(ptr, value, bitPtr) \ +do {\ + while (bitPtr < 32) {\ + bitPtr += 8;\ + *ptr++ = (OI_UINT8)(value >> 24);\ + value <<= 8;\ + }\ +} while (0) + +/** +@} +*/ + +#endif /* _OI_BITSTREAM_H */ diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_bt_spec.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_bt_spec.h new file mode 100644 index 0000000000..b98a5821dd --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_bt_spec.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_BT_SPEC_H +#define _OI_BT_SPEC_H +/** + * @file + * + * This file contains common definitions from the Bluetooth specification. + * + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#include "oi_stddefs.h" + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** The maximum number of active slaves in a piconet. */ +#define OI_BT_MAX_ACTIVE_SLAVES 7 + +/** the number of bytes in a Bluetooth device address (BD_ADDR) */ +#define OI_BD_ADDR_BYTE_SIZE 6 + +/** + * 48-bit Bluetooth device address + * + * Because 48-bit integers may not be supported on all platforms, the + * address is defined as an array of bytes. This array is big-endian, + * meaning that + * - array[0] contains bits 47-40, + * - array[1] contains bits 39-32, + * - array[2] contains bits 31-24, + * - array[3] contains bits 23-16, + * - array[4] contains bits 15-8, and + * - array[5] contains bits 7-0. + */ +typedef struct { + OI_UINT8 addr[OI_BD_ADDR_BYTE_SIZE] ; /**< Bluetooth device address represented as an array of 8-bit values */ +} OI_BD_ADDR ; + +/** + * @name Data types for working with UUIDs + * UUIDs are 16 bytes (128 bits). + * + * To avoid having to pass around 128-bit values all the time, 32-bit and 16-bit + * UUIDs are defined, along with a mapping from the shorter versions to the full + * version. + * + * @{ + */ + +/** + * 16-bit representation of a 128-bit UUID + */ +typedef OI_UINT16 OI_UUID16; + +/** + * 32-bit representation of a 128-bit UUID + */ +typedef OI_UINT32 OI_UUID32; + +/** + * number of bytes in a 128 bit UUID + */ +#define OI_BT_UUID128_SIZE 16 + +/** + * number of bytes in IPv6 style addresses + */ +#define OI_BT_IPV6ADDR_SIZE 16 + +/** + * type definition for a 128-bit UUID + * + * To simplify conversion between 128-bit UUIDs and 16-bit and 32-bit UUIDs, + * the most significant 32 bits are stored with the same endian-ness as is + * native on the target (local) device. The remainder of the 128-bit UUID is + * stored as bytes in big-endian order. + */ +typedef struct { + OI_UINT32 ms32bits; /**< most significant 32 bits of 128-bit UUID */ + OI_UINT8 base[OI_BT_UUID128_SIZE - sizeof(OI_UINT32)]; /**< remainder of 128-bit UUID, array of 8-bit values */ +} OI_UUID128; + +/** @} */ + +/** number of bytes in a link key */ +#define OI_BT_LINK_KEY_SIZE 16 + +/** + * type definition for a baseband link key + * + * Because 128-bit integers may not be supported on all platforms, we define + * link keys as an array of bytes. Unlike the Bluetooth device address, + * the link key is stored in little-endian order, meaning that + * - array[0] contains bits 0 - 7, + * - array[1] contains bits 8 - 15, + * - array[2] contains bits 16 - 23, + * - array[3] contains bits 24 - 31, + * - array[4] contains bits 32 - 39, + * - array[5] contains bits 40 - 47, + * - array[6] contains bits 48 - 55, + * - array[7] contains bits 56 - 63, + * - array[8] contains bits 64 - 71, + * - array[9] contains bits 72 - 79, + * - array[10] contains bits 80 - 87, + * - array[11] contains bits 88 - 95, + * - array[12] contains bits 96 - 103, + * - array[13] contains bits 104- 111, + * - array[14] contains bits 112- 119, and + * - array[15] contains bits 120- 127. + */ +typedef struct { + OI_UINT8 key[OI_BT_LINK_KEY_SIZE] ; /**< link key represented as an array of 8-bit values */ +} OI_LINK_KEY ; + + +/** Out-of-band data size - C and R values are 16-bytes each */ +#define OI_BT_OOB_NUM_BYTES 16 + +typedef struct { + OI_UINT8 value[OI_BT_OOB_NUM_BYTES] ; /**< same struct used for C and R values */ +} OI_OOB_DATA ; + + +/** + * link key types + */ +typedef enum { + OI_LINK_KEY_TYPE_COMBO = 0, /**< combination key */ + OI_LINK_KEY_TYPE_LOCAL_UNIT = 1, /**< local unit key */ + OI_LINK_KEY_TYPE_REMOTE_UNIT = 2, /**< remote unit key */ + OI_LINK_KEY_TYPE_DEBUG_COMBO = 3, /**< debug combination key */ + OI_LINK_KEY_TYPE_UNAUTHENTICATED = 4, /**< Unauthenticated */ + OI_LINK_KEY_TYPE_AUTHENTICATED = 5, /**< Authenticated */ + OI_LINK_KEY_TYPE_CHANGED_COMBO = 6 /**< Changed */ + +} OI_BT_LINK_KEY_TYPE ; + + +/** amount of space allocated for a PIN (personal indentification number) in bytes */ +#define OI_BT_PIN_CODE_SIZE 16 + +/** data type for a PIN (PINs are treated as strings, so endianness does not apply.) */ +typedef struct { + OI_UINT8 pin[OI_BT_PIN_CODE_SIZE] ; /**< PIN represented as an array of 8-bit values */ +} OI_PIN_CODE ; + +/** maximum number of SCO connections per device, which is 3 as of version 2.0+EDR + of the Bluetooth specification (see sec 4.3 of vol 2 part B) */ +#define OI_BT_MAX_SCO_CONNECTIONS 3 + +/** data type for clock offset */ +typedef OI_UINT16 OI_BT_CLOCK_OFFSET ; + +/** data type for a LM handle */ +typedef OI_UINT16 OI_HCI_LM_HANDLE; + +/** opaque data type for a SCO or ACL connection handle */ +typedef struct _OI_HCI_CONNECTION *OI_HCI_CONNECTION_HANDLE; + +/** data type for HCI Error Code, as defined in oi_hcispec.h */ +typedef OI_UINT8 OI_HCI_ERROR_CODE ; + +/** + * The Bluetooth device type is indicated by a 24-bit bitfield, represented as a + * 32-bit number in the stack. The bit layout and values for device class are specified + * in the file oi_bt_assigned_nos.h and in the Bluetooth "Assigned Numbers" specification + * at http://www.bluetooth.org/assigned-numbers/. + */ +typedef OI_UINT32 OI_BT_DEVICE_CLASS ; + +#define OI_BT_DEV_CLASS_FORMAT_MASK 0x000003 /**< Bits 0-1 contain format type. */ +#define OI_BT_DEV_CLASS_MINOR_DEVICE_MASK 0x0000FC /**< Bits 2-7 contain minor device class value. */ +#define OI_BT_DEV_CLASS_MAJOR_DEVICE_MASK 0x001F00 /**< Bits 8-12 contain major device class value. */ +#define OI_BT_DEV_CLASS_MAJOR_SERVICE_MASK 0xFFE000 /**< Bits 13-23 contain major service class value. */ + +/** There is currently only one device class format defined, type 00. */ +#define OI_BT_DEV_CLASS_FORMAT_TYPE 00 + +/** Bit 13 in device class indicates limited discoverability mode (GAP v2.0+EDR, section 4.1.2.2) */ +#define OI_BT_DEV_CLASS_LIMITED_DISCO_BIT BIT13 + +/** macro to test validity of the Device Class Format */ +#define OI_BT_VALID_DEVICE_CLASS_FORMAT(class) (OI_BT_DEV_CLASS_FORMAT_TYPE == ((class) & OI_BT_DEV_CLASS_FORMAT_MASK)) + +/** the time between baseband clock ticks, currently 625 microseconds (one slot) */ +#define OI_BT_TICK 625 +/** some macros to convert to/from baseband clock ticks - use no floating point! */ +#define OI_SECONDS_TO_BT_TICKS(secs) ((secs)*1600) +#define OI_BT_TICKS_TO_SECONDS(ticks) ((ticks)/1600) +#define OI_MSECS_TO_BT_TICKS(msecs) (((msecs)*8)/5) +#define OI_BT_TICKS_TO_MSECS(ticks) (((ticks)*5)/8) + +/** EIR byte order */ +#define OI_EIR_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER + + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +/*****************************************************************************/ +#endif /* _OI_BT_SPEC_H */ diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h new file mode 100644 index 0000000000..a3f7d87516 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc.h @@ -0,0 +1,484 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#ifndef _OI_CODEC_SBC_CORE_H +#define _OI_CODEC_SBC_CORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** +@file +Declarations of codec functions, data types, and macros. + +@ingroup codec_lib +*/ + +/** +@addtogroup codec_lib +@{ +*/ + +/* Non-BM3 users of of the codec must include oi_codec_sbc_bm3defs.h prior to + * including this file, or else these includes will fail because the BM3 SDK is + * not in the include path */ +#ifndef _OI_CODEC_SBC_BM3DEFS_H +#include "oi_stddefs.h" +#include "oi_status.h" +#endif + +#include + +#define SBC_MAX_CHANNELS 2 +#define SBC_MAX_BANDS 8 +#define SBC_MAX_BLOCKS 16 +#define SBC_MIN_BITPOOL 2 /**< Minimum size of the bit allocation pool used to encode the stream */ +#define SBC_MAX_BITPOOL 250 /**< Maximum size of the bit allocation pool used to encode the stream */ +#define SBC_MAX_ONE_CHANNEL_BPS 320000 +#define SBC_MAX_TWO_CHANNEL_BPS 512000 + + +#define SBC_WBS_BITRATE 62000 +#define SBC_WBS_BITPOOL 27 +#define SBC_WBS_NROF_BLOCKS 16 +#define SBC_WBS_FRAME_LEN 62 +#define SBC_WBS_SAMPLES_PER_FRAME 128 + + +#define SBC_HEADER_LEN 4 +#define SBC_MAX_FRAME_LEN (SBC_HEADER_LEN + \ + ((SBC_MAX_BANDS * SBC_MAX_CHANNELS / 2) + \ + (SBC_MAX_BANDS + SBC_MAX_BLOCKS * SBC_MAX_BITPOOL + 7)/8)) +#define SBC_MAX_SAMPLES_PER_FRAME (SBC_MAX_BANDS * SBC_MAX_BLOCKS) + +#define SBC_MAX_SCALEFACTOR_BYTES ((4*(SBC_MAX_CHANNELS * SBC_MAX_BANDS) + 7)/8) + +#define OI_SBC_SYNCWORD 0x9c +#define OI_SBC_ENHANCED_SYNCWORD 0x9d + +/**@name Sampling frequencies */ +/**@{*/ +#define SBC_FREQ_16000 0 /**< The sampling frequency is 16 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_FREQ_32000 1 /**< The sampling frequency is 32 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_FREQ_44100 2 /**< The sampling frequency is 44.1 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_FREQ_48000 3 /**< The sampling frequency is 48 kHz. One possible value for the @a frequency parameter of OI_CODEC_SBC_EncoderConfigure() */ +/**@}*/ + +/**@name Channel modes */ +/**@{*/ +#define SBC_MONO 0 /**< The mode of the encoded channel is mono. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_DUAL_CHANNEL 1 /**< The mode of the encoded channel is dual-channel. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_STEREO 2 /**< The mode of the encoded channel is stereo. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_JOINT_STEREO 3 /**< The mode of the encoded channel is joint stereo. One possible value for the @a mode parameter of OI_CODEC_SBC_EncoderConfigure() */ +/**@}*/ + +/**@name Subbands */ +/**@{*/ +#define SBC_SUBBANDS_4 0 /**< The encoded stream has 4 subbands. One possible value for the @a subbands parameter of OI_CODEC_SBC_EncoderConfigure()*/ +#define SBC_SUBBANDS_8 1 /**< The encoded stream has 8 subbands. One possible value for the @a subbands parameter of OI_CODEC_SBC_EncoderConfigure() */ +/**@}*/ + +/**@name Block lengths */ +/**@{*/ +#define SBC_BLOCKS_4 0 /**< A block size of 4 blocks was used to encode the stream. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_BLOCKS_8 1 /**< A block size of 8 blocks was used to encode the stream is. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_BLOCKS_12 2 /**< A block size of 12 blocks was used to encode the stream. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_BLOCKS_16 3 /**< A block size of 16 blocks was used to encode the stream. One possible value for the @a blocks parameter of OI_CODEC_SBC_EncoderConfigure() */ +/**@}*/ + +/**@name Bit allocation methods */ +/**@{*/ +#define SBC_LOUDNESS 0 /**< The bit allocation method. One possible value for the @a loudness parameter of OI_CODEC_SBC_EncoderConfigure() */ +#define SBC_SNR 1 /**< The bit allocation method. One possible value for the @a loudness parameter of OI_CODEC_SBC_EncoderConfigure() */ +/**@}*/ + +/** +@} + +@addtogroup codec_internal +@{ +*/ + +typedef OI_INT16 SBC_BUFFER_T; + + +/** Used internally. */ +typedef struct { + OI_UINT16 frequency; /**< The sampling frequency. Input parameter. */ + OI_UINT8 freqIndex; + + OI_UINT8 nrof_blocks; /**< The block size used to encode the stream. Input parameter. */ + OI_UINT8 blocks; + + + OI_UINT8 nrof_subbands; /**< The number of subbands of the encoded stream. Input parameter. */ + OI_UINT8 subbands; + + OI_UINT8 mode; /**< The mode of the encoded channel. Input parameter. */ + OI_UINT8 nrof_channels; /**< The number of channels of the encoded stream. */ + + OI_UINT8 alloc; /**< The bit allocation method. Input parameter. */ + OI_UINT8 bitpool; /**< Size of the bit allocation pool used to encode the stream. Input parameter. */ + OI_UINT8 crc; /**< Parity check byte used for error detection. */ + OI_UINT8 join; /**< Whether joint stereo has been used. */ + OI_UINT8 enhanced; + OI_UINT8 min_bitpool; /**< This value is only used when encoding. SBC_MAX_BITPOOL if variable + bitpools are disallowed, otherwise the minimum bitpool size that will + be used by the bit allocator. */ + + OI_UINT8 cachedInfo; /**< Information about the previous frame */ +} OI_CODEC_SBC_FRAME_INFO; + +/** Used internally. */ +typedef struct { + const OI_CHAR *codecInfo; + OI_CODEC_SBC_FRAME_INFO frameInfo; + OI_INT8 scale_factor[SBC_MAX_CHANNELS * SBC_MAX_BANDS]; + OI_UINT32 frameCount; + OI_INT32 *subdata; + + SBC_BUFFER_T *filterBuffer[SBC_MAX_CHANNELS]; + OI_INT32 filterBufferLen; + OI_UINT filterBufferOffset; + + union { + OI_UINT8 uint8[SBC_MAX_CHANNELS * SBC_MAX_BANDS]; + OI_UINT32 uint32[SBC_MAX_CHANNELS * SBC_MAX_BANDS / 4]; + } bits; + OI_UINT8 maxBitneed; /**< Running maximum bitneed */ + OI_BYTE formatByte; + OI_UINT8 pcmStride; + OI_UINT8 maxChannels; +} OI_CODEC_SBC_COMMON_CONTEXT; + + +/* + * A smaller value reduces RAM usage at the expense of increased CPU usage. Values in the range + * 27..50 are recommended, beyond 50 there is a diminishing return on reduced CPU usage. + */ +#define SBC_CODEC_MIN_FILTER_BUFFERS 16 +#define SBC_CODEC_FAST_FILTER_BUFFERS 27 + +/* Expands to the number of OI_UINT32s needed to ensure enough memory to encode + * or decode streams of numChannels channels, using numBuffers buffers. + * Example: + * OI_UINT32 decoderData[CODEC_DATA_WORDS(SBC_MAX_CHANNELS, SBC_DECODER_FAST_SYNTHESIS_BUFFERS)]; + * */ +#define CODEC_DATA_WORDS(numChannels, numBuffers) \ + ((\ + (sizeof(OI_INT32) * SBC_MAX_BLOCKS * numChannels * SBC_MAX_BANDS) \ + + (sizeof(SBC_BUFFER_T) * SBC_MAX_CHANNELS * SBC_MAX_BANDS * numBuffers) \ + + (sizeof (OI_UINT32) - 1) \ + ) / sizeof(OI_UINT32)) + +/** Opaque parameter to decoding functions; maintains decoder context. */ +typedef struct { + OI_CODEC_SBC_COMMON_CONTEXT common; + OI_UINT8 limitFrameFormat; /* Boolean, set by OI_CODEC_SBC_DecoderLimit() */ + OI_UINT8 restrictSubbands; + OI_UINT8 enhancedEnabled; + OI_UINT8 bufferedBlocks; +} OI_CODEC_SBC_DECODER_CONTEXT; + +typedef struct { + OI_UINT32 data[CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS)]; +} OI_CODEC_SBC_CODEC_DATA_MONO; + +typedef struct { + OI_UINT32 data[CODEC_DATA_WORDS(2, SBC_CODEC_FAST_FILTER_BUFFERS)]; +} OI_CODEC_SBC_CODEC_DATA_STEREO; + +/** +@} + +@addtogroup codec_lib +@{ +*/ + +/** + * This function resets the decoder. The context must be reset when + * changing streams, or if the following stream parameters change: + * number of subbands, stereo mode, or frequency. + * + * @param context Pointer to the decoder context structure to be reset. + * + * @param enhanced If true, enhanced SBC operation is enabled. If enabled, + * the codec will recognize the alternative syncword for + * decoding an enhanced SBC stream. Enhancements should not + * be enabled unless the stream is known to be generated + * by an enhanced encoder, or there is a small possibility + * for decoding glitches if synchronization were to be lost. + */ +OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT32 *decoderData, + OI_UINT32 decoderDataBytes, + OI_UINT8 maxChannels, + OI_UINT8 pcmStride, + OI_BOOL enhanced); + +/** + * This function restricts the kind of SBC frames that the Decoder will + * process. Its use is optional. If used, it must be called after + * calling OI_CODEC_SBC_DecoderReset(). After it is called, any calls + * to OI_CODEC_SBC_DecodeFrame() with SBC frames that do not conform + * to the Subband and Enhanced SBC setting will be rejected with an + * OI_STATUS_INVALID_PARAMETERS return. + * + * @param context Pointer to the decoder context structure to be limited. + * + * @param enhanced If true, all frames passed to the decoder must be + * Enhanced SBC frames. If false, all frames must be + * standard SBC frames. + * + * @param subbands May be set to SBC_SUBBANDS_4 or SBC_SUBBANDS_8. All + * frames passed to the decoder must be encoded with + * the requested number of subbands. + * + */ +OI_STATUS OI_CODEC_SBC_DecoderLimit(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_BOOL enhanced, + OI_UINT8 subbands); + +/** + * This function sets the decoder parameters for a raw decode where the decoder parameters are not + * available in the sbc data stream. OI_CODEC_SBC_DecoderReset must be called + * prior to calling this function. + * + * @param context Decoder context structure. This must be the context must be + * used each time a frame is decoded. + * + * @param enhanced Set to TRUE to enable Qualcomm proprietary + * quality enhancements. + * + * @param frequency One of SBC_FREQ_16000, SBC_FREQ_32000, SBC_FREQ_44100, + * SBC_FREQ_48000 + * + * @param mode One of SBC_MONO, SBC_DUAL_CHANNEL, SBC_STEREO, + * SBC_JOINT_STEREO + * + * @param subbands One of SBC_SUBBANDS_4, SBC_SUBBANDS_8 + * + * @param blocks One of SBC_BLOCKS_4, SBC_BLOCKS_8, SBC_BLOCKS_12, + * SBC_BLOCKS_16 + * + * @param alloc One of SBC_LOUDNESS, SBC_SNR + * + * @param maxBitpool The maximum bitpool size for this context + */ +OI_STATUS OI_CODEC_SBC_DecoderConfigureRaw(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_BOOL enhanced, + OI_UINT8 frequency, + OI_UINT8 mode, + OI_UINT8 subbands, + OI_UINT8 blocks, + OI_UINT8 alloc, + OI_UINT8 maxBitpool); + +/** + * Decode one SBC frame. The frame has no header bytes. The context must have been previously + * initialized by calling OI_CODEC_SBC_DecoderConfigureRaw(). + * + * @param context Pointer to a decoder context structure. The same context + * must be used each time when decoding from the same stream. + * + * @param bitpool The actual bitpool size for this frame. Must be <= the maxbitpool specified + * in the call to OI_CODEC_SBC_DecoderConfigureRaw(), + * + * @param frameData Address of a pointer to the SBC data to decode. This + * value will be updated to point to the next frame after + * successful decoding. + * + * @param frameBytes Pointer to a UINT32 containing the number of available + * bytes of frame data. This value will be updated to reflect + * the number of bytes remaining after a decoding operation. + * + * @param pcmData Address of an array of OI_INT16 pairs, which will be + * populated with the decoded audio data. This address + * is not updated. + * + * @param pcmBytes Pointer to a UINT32 in/out parameter. On input, it + * should contain the number of bytes available for pcm + * data. On output, it will contain the number of bytes + * written. Note that this differs from the semantics of + * frameBytes. + */ +OI_STATUS OI_CODEC_SBC_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT8 bitpool, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes, + OI_INT16 *pcmData, + OI_UINT32 *pcmBytes); + +/** + * Decode one SBC frame. + * + * @param context Pointer to a decoder context structure. The same context + * must be used each time when decoding from the same stream. + * + * @param frameData Address of a pointer to the SBC data to decode. This + * value will be updated to point to the next frame after + * successful decoding. + * + * @param frameBytes Pointer to a UINT32 containing the number of available + * bytes of frame data. This value will be updated to reflect + * the number of bytes remaining after a decoding operation. + * + * @param pcmData Address of an array of OI_INT16 pairs, which will be + * populated with the decoded audio data. This address + * is not updated. + * + * @param pcmBytes Pointer to a UINT32 in/out parameter. On input, it + * should contain the number of bytes available for pcm + * data. On output, it will contain the number of bytes + * written. Note that this differs from the semantics of + * frameBytes. + */ +OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes, + OI_INT16 *pcmData, + OI_UINT32 *pcmBytes); + +/** + * Calculate the number of SBC frames but don't decode. CRC's are not checked, + * but the Sync word is found prior to count calculation. + * + * @param frameData Pointer to the SBC data. + * + * @param frameBytes Number of bytes avaiable in the frameData buffer + * + */ +OI_UINT8 OI_CODEC_SBC_FrameCount(OI_BYTE *frameData, + OI_UINT32 frameBytes); + +/** + * Analyze an SBC frame but don't do the decode. + * + * @param context Pointer to a decoder context structure. The same context + * must be used each time when decoding from the same stream. + * + * @param frameData Address of a pointer to the SBC data to decode. This + * value will be updated to point to the next frame after + * successful decoding. + * + * @param frameBytes Pointer to a UINT32 containing the number of available + * bytes of frame data. This value will be updated to reflect + * the number of bytes remaining after a decoding operation. + * + */ +OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes); + +/* Common functions */ + +/** + Calculate the frame length. + + @param frame The frame whose length to calculate + + @return the length of an individual encoded frame in + bytes + */ +OI_UINT16 OI_CODEC_SBC_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame); + + +/** + * Calculate the maximum bitpool size that fits within a given frame length. + * + * @param frame The frame to calculate the bitpool size for + * @param frameLen The frame length to fit the bitpool to + * + * @return the maximum bitpool that will fit in the specified frame length + */ +OI_UINT16 OI_CODEC_SBC_CalculateBitpool(OI_CODEC_SBC_FRAME_INFO *frame, + OI_UINT16 frameLen); + +/** + Calculate the bit rate. + + @param frame The frame whose bit rate to calculate + + @return the approximate bit rate in bits per second, + assuming that stream parameters are constant + */ +OI_UINT32 OI_CODEC_SBC_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame); + +/** + Calculate decoded audio data length for one frame. + + @param frame The frame whose audio data length to calculate + + @return length of decoded audio data for a + single frame, in bytes + */ +OI_UINT16 OI_CODEC_SBC_CalculatePcmBytes(OI_CODEC_SBC_COMMON_CONTEXT *common); + +/** + * Get the codec version text. + * + * @return pointer to text string containing codec version text + * + */ +OI_CHAR *OI_CODEC_Version(void); + + +/** +@} + +@addtogroup codec_internal +@{ +*/ + +extern const OI_CHAR *const OI_CODEC_SBC_FreqText[]; +extern const OI_CHAR *const OI_CODEC_SBC_ModeText[]; +extern const OI_CHAR *const OI_CODEC_SBC_SubbandsText[]; +extern const OI_CHAR *const OI_CODEC_SBC_BlocksText[]; +extern const OI_CHAR *const OI_CODEC_SBC_AllocText[]; + +/** +@} + +@addtogroup codec_lib +@{ +*/ + +#ifdef OI_DEBUG +void OI_CODEC_SBC_DumpConfig(OI_CODEC_SBC_FRAME_INFO *frameInfo); +#else +#define OI_CODEC_SBC_DumpConfig(f) +#endif + +/** +@} +*/ + +#ifdef __cplusplus +} +#endif + + +#endif /* _OI_CODEC_SBC_CORE_H */ + + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h new file mode 100644 index 0000000000..4e3897614f --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_codec_sbc_private.h @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_CODEC_SBC_PRIVATE_H +#define _OI_CODEC_SBC_PRIVATE_H + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +/** +@file +Function prototypes and macro definitions used internally by the codec. + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +#ifdef USE_RESTRICT_KEYWORD +#define RESTRICT restrict +#else +#define RESTRICT +#endif + +#ifdef CODEC_DEBUG +#include +#define ERROR(x) do { printf x; printf("\n"); } while (0) +#else +#define ERROR(x) +#endif + +#ifdef TRACE_EXECUTION +#define TRACE(x) do { printf x; printf("\n"); } while (0) +#else +#define TRACE(x) +#endif + +#ifndef PRIVATE +#define PRIVATE +#endif + +#ifndef INLINE +#define INLINE +#endif + +#include "oi_assert.h" +#include "oi_codec_sbc.h" + +#ifndef OI_SBC_SYNCWORD +#define OI_SBC_SYNCWORD 0x9c +#endif + +#ifndef DIVIDE +#define DIVIDE(a, b) ((a) / (b)) +#endif + +typedef union { + OI_UINT8 uint8[SBC_MAX_BANDS]; + OI_UINT32 uint32[SBC_MAX_BANDS / 4]; +} BITNEED_UNION1; + +typedef union { + OI_UINT8 uint8[2 * SBC_MAX_BANDS]; + OI_UINT32 uint32[2 * SBC_MAX_BANDS / 4]; +} BITNEED_UNION2; + +static const OI_UINT16 freq_values[] = { 16000, 32000, 44100, 48000 }; +static const OI_UINT8 block_values[] = { 4, 8, 12, 16 }; +static const OI_UINT8 channel_values[] = { 1, 2, 2, 2 }; +static const OI_UINT8 band_values[] = { 4, 8 }; + + +#define TEST_MODE_SENTINEL "OINA" +#define TEST_MODE_SENTINEL_LENGTH 4 + +/** Used internally. */ +typedef struct { + union { + const OI_UINT8 *r; + OI_UINT8 *w; + } ptr; + OI_UINT32 value; + OI_UINT bitPtr; +} OI_BITSTREAM; + + +#define VALID_INT16(x) (((x) >= OI_INT16_MIN) && ((x) <= OI_INT16_MAX)) +#define VALID_INT32(x) (((x) >= OI_INT32_MIN) && ((x) <= OI_INT32_MAX)) + +#define DCTII_8_SHIFT_IN 0 +#define DCTII_8_SHIFT_OUT 16-DCTII_8_SHIFT_IN + +#define DCTII_8_SHIFT_0 (DCTII_8_SHIFT_OUT) +#define DCTII_8_SHIFT_1 (DCTII_8_SHIFT_OUT) +#define DCTII_8_SHIFT_2 (DCTII_8_SHIFT_OUT) +#define DCTII_8_SHIFT_3 (DCTII_8_SHIFT_OUT) +#define DCTII_8_SHIFT_4 (DCTII_8_SHIFT_OUT) +#define DCTII_8_SHIFT_5 (DCTII_8_SHIFT_OUT) +#define DCTII_8_SHIFT_6 (DCTII_8_SHIFT_OUT-1) +#define DCTII_8_SHIFT_7 (DCTII_8_SHIFT_OUT-2) + +#define DCT_SHIFT 15 + +#define DCTIII_4_SHIFT_IN 2 +#define DCTIII_4_SHIFT_OUT 15 + +#define DCTIII_8_SHIFT_IN 3 +#define DCTIII_8_SHIFT_OUT 14 + +OI_UINT computeBitneed(OI_CODEC_SBC_COMMON_CONTEXT *common, + OI_UINT8 *bitneeds, + OI_UINT ch, + OI_UINT *preferredBitpool); + +void oneChannelBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common, + BITNEED_UNION1 *bitneeds, + OI_UINT ch, + OI_UINT bitcount); + + +OI_INT adjustToFitBitpool(const OI_UINT bitpool, + OI_UINT32 *bitneeds, + const OI_UINT subbands, + OI_UINT bitcount, + OI_UINT *excess); + +INLINE OI_INT allocAdjustedBits(OI_UINT8 *dest, + OI_INT bits, + OI_INT excess); + +INLINE OI_INT allocExcessBits(OI_UINT8 *dest, + OI_INT excess); + +PRIVATE OI_UINT32 internal_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame); + +PRIVATE OI_UINT16 internal_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame); + +void monoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common); + +typedef void (*BIT_ALLOC)(OI_CODEC_SBC_COMMON_CONTEXT *common); + +PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT8 bitpool, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes, + OI_INT16 *pcmData, + OI_UINT32 *pcmBytes); + +INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT32 *decoderData, + OI_UINT32 decoderDataBytes, + OI_BYTE maxChannels, + OI_BYTE pcmStride, + OI_BOOL enhanced); + +INLINE OI_UINT16 OI_SBC_CalculateFrameAndHeaderlen(OI_CODEC_SBC_FRAME_INFO *frame, OI_UINT *headerLen_); + +PRIVATE OI_UINT32 OI_SBC_MaxBitpool(OI_CODEC_SBC_FRAME_INFO *frame); + +PRIVATE void OI_SBC_ComputeBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *frame); +PRIVATE OI_UINT8 OI_SBC_CalculateChecksum(OI_CODEC_SBC_FRAME_INFO *frame, OI_BYTE const *data); + +/* Transform functions */ +PRIVATE void shift_buffer(SBC_BUFFER_T *dest, SBC_BUFFER_T *src, OI_UINT wordCount); +PRIVATE void cosineModulateSynth4(SBC_BUFFER_T *RESTRICT out, OI_INT32 const *RESTRICT in); +PRIVATE void SynthWindow40_int32_int32_symmetry_with_sum(OI_INT16 *pcm, SBC_BUFFER_T buffer[80], OI_UINT strideShift); + +INLINE void dct3_4(OI_INT32 *RESTRICT out, OI_INT32 const *RESTRICT in); +PRIVATE void analyze4_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 40], + OI_INT16 *pcm, + OI_UINT strideShift, + OI_INT32 subband[4]); + +INLINE void dct3_8(OI_INT32 *RESTRICT out, OI_INT32 const *RESTRICT in); + +PRIVATE void analyze8_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 80], + OI_INT16 *pcm, + OI_UINT strideShift, + OI_INT32 subband[8]); + +#ifdef SBC_ENHANCED +PRIVATE void analyze8_enhanced_generated(SBC_BUFFER_T analysisBuffer[RESTRICT 112], + OI_INT16 *pcm, + OI_UINT strideShift, + OI_INT32 subband[8]); +#endif + +/* Decoder functions */ + +INLINE void OI_SBC_ReadHeader(OI_CODEC_SBC_COMMON_CONTEXT *common, const OI_BYTE *data); +PRIVATE void OI_SBC_ReadScalefactors(OI_CODEC_SBC_COMMON_CONTEXT *common, const OI_BYTE *b, OI_BITSTREAM *bs); +PRIVATE void OI_SBC_ReadSamples(OI_CODEC_SBC_DECODER_CONTEXT *common, OI_BITSTREAM *ob); +PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *common, OI_BITSTREAM *global_bs); +PRIVATE void OI_SBC_SynthFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT start_block, OI_UINT nrof_blocks); +INLINE OI_INT32 OI_SBC_Dequant(OI_UINT32 raw, OI_UINT scale_factor, OI_UINT bits); +PRIVATE OI_BOOL OI_SBC_ExamineCommandPacket(OI_CODEC_SBC_DECODER_CONTEXT *context, const OI_BYTE *data, OI_UINT32 len); +PRIVATE void OI_SBC_GenerateTestSignal(OI_INT16 pcmData[][2], OI_UINT32 sampleCount); + +PRIVATE void OI_SBC_ExpandFrameFields(OI_CODEC_SBC_FRAME_INFO *frame); +PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT *common, + OI_UINT32 *codecDataAligned, + OI_UINT32 codecDataBytes, + OI_UINT8 maxChannels, + OI_UINT8 pcmStride); +/** +@} +*/ + +#endif /* _OI_CODEC_SBC_PRIVATE_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_common.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_common.h new file mode 100644 index 0000000000..c4169f932c --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_common.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_COMMON_H +#define _OI_COMMON_H +/** + * @file + * + * This file is used to group commonly used BLUEmagic 3.0 software + * header files. + * + * This file should be included in application source code along with the header + * files for the specific modules of the protocol stack being used. + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#include "oi_bt_spec.h" +#include "oi_stddefs.h" +#include "oi_status.h" +#include "oi_time.h" +#include "oi_osinterface.h" + + +/*****************************************************************************/ +#endif /* _OI_COMMON_H */ diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h new file mode 100644 index 0000000000..dfa52c16b5 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_cpu_dep.h @@ -0,0 +1,505 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_CPU_DEP_H +#define _OI_CPU_DEP_H +/** + * @file + * This file contains definitions for characteristics of the target CPU and + * compiler, including primitive data types and endianness. + * + * This file defines the byte order and primitive data types for various + * CPU families. The preprocessor symbol 'CPU' must be defined to be an + * appropriate value or this header will generate a compile-time error. + * + * @note The documentation for this header file uses the x86 family of processors + * as an illustrative example for CPU/compiler-dependent data type definitions. + * Go to the source code of this header file to see the details of primitive type + * definitions for each platform. + * + * Additional information is available in the @ref data_types_docpage section. + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +/** @name Definitions indicating family of target OI_CPU_TYPE + * @{ + */ + +#define OI_CPU_X86 1 /**< x86 processor family */ +#define OI_CPU_ARM 2 /**< ARM processor family. + @deprecated Use #OI_CPU_ARM7_LEND or + #OI_CPU_ARM7_BEND. */ +#define OI_CPU_ARC 3 /**< ARC processor family. + @deprecated Use #OI_CPU_ARC_LEND or + #OI_CPU_ARC_BEND. */ +#define OI_CPU_SH3 4 /**< Hitachi SH-3 processor family */ +#define OI_CPU_H8 5 /**< Hitachi H8 processor family */ +#define OI_CPU_MIPS 6 /**< MIPS processor family */ +#define OI_CPU_SPARC 7 /**< SPARC processor family */ +#define OI_CPU_M68000 8 /**< Motorola M68000 processor family */ +#define OI_CPU_PPC 9 /**< PowerPC (PPC) processor family */ +#define OI_CPU_SH4_7750 10 /**< Hitachi SH7750 series in SH-4 processor family */ +#define OI_CPU_SH2 11 /**< Hitachi SH-2 processor family */ +#define OI_CPU_ARM7_LEND 12 /**< ARM7, little-endian */ +#define OI_CPU_ARM7_BEND 13 /**< ARM7, big-endian */ +#define OI_CPU_GDM1202 14 /**< GCT GDM1202 */ +#define OI_CPU_ARC_LEND 15 /**< ARC processor family, little-endian */ +#define OI_CPU_ARC_BEND 16 /**< ARC processor family, big-endian */ +#define OI_CPU_M30833F 17 /**< Mitsubishi M308 processor family */ +#define OI_CPU_CR16C 18 /**< National Semiconductor 16 bit processor family */ +#define OI_CPU_M64111 19 /**< Renesas M64111 processor (M32R family) */ +#define OI_CPU_ARMV5_LEND 20 //*< ARM5, little-endian */ + +#define OI_CPU_TYPE 12 + +#ifndef OI_CPU_TYPE +#error "OI_CPU_TYPE type not defined" +#endif + +/**@}*/ + + +/** @name Definitions indicating byte-wise endianness of target CPU + * @{ + */ + +#define OI_BIG_ENDIAN_BYTE_ORDER 0 /**< Multiple-byte values are stored in memory beginning with the most significant byte at the lowest address. */ +#define OI_LITTLE_ENDIAN_BYTE_ORDER 1 /**< Multiple-byte values are stored in memory beginning with the least significant byte at the lowest address. */ + +/**@}*/ + + +/** @name CPU/compiler-independent primitive data type definitions + * @{ + */ + +typedef int OI_BOOL; /**< Boolean values use native integer data type for target CPU. */ +typedef int OI_INT; /**< Integer values use native integer data type for target CPU. */ +typedef unsigned int OI_UINT; /**< Unsigned integer values use native unsigned integer data type for target CPU. */ +typedef unsigned char OI_BYTE; /**< Raw bytes type uses native character data type for target CPU. */ + +/**@}*/ + + + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_X86 + +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER /**< x86 platform byte ordering is little-endian */ + +/** @name CPU/compiler-dependent primitive data type definitions for x86 processor family + * @{ + */ +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for x86 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for x86 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for x86 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for x86 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for x86 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for x86 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_ARM +/* This CPU type is deprecated (removed from use). Instead, use OI_CPU_ARM7_LEND or OI_CPU_ARM7_BEND for + little-endian or big-endian configurations of the ARM7, respectively. */ +#error OI_CPU_ARM is deprecated +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_ARC +/* This CPU type is deprecated (removed from use). Instead, use OI_CPU_ARC_LEND or OI_CPU_ARC_BEND for + little-endian or big-endian configurations of the ARC, respectively. */ +#error OI_CPU_ARC is deprecated +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_SH3 +/* The Hitachi SH C compiler defines _LIT or _BIG, depending on the endianness + specified to the compiler on the command line. */ +#if defined(_LIT) +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER /**< If _LIT is defined, SH-3 platform byte ordering is little-endian. */ +#elif defined(_BIG) +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER /**< If _BIG is defined, SH-3 platform byte ordering is big-endian. */ +#else +#error SH compiler endianness undefined +#endif + +/** @name CPU/compiler-dependent primitive data type definitions for SH-3 processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for SH-3 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for SH-3 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for SH-3 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for SH-3 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for SH-3 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for SH-3 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_SH2 + +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER /**< SH-2 platform byte ordering is big-endian. */ + +/** @name CPU/compiler-dependent primitive data type definitions for SH-2 processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for SH-2 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for SH-2 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for SH-2 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for SH-2 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for SH-2 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for SH-2 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_H8 +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER +#error basic types not defined +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_MIPS +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER +/** @name CPU/compiler-dependent primitive data type definitions for MIPS processor family + * @{ + */ +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for ARM7 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for ARM7 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for ARM7 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for ARM7 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for ARM7 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for ARM7 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_SPARC +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER +#error basic types not defined +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_M68000 +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER /**< M68000 platform byte ordering is big-endian. */ + +/** @name CPU/compiler-dependent primitive data type definitions for M68000 processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for M68000 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for M68000 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for M68000 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for M68000 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for M68000 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for M68000 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_PPC +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER + + +/** @name CPU/compiler-dependent primitive data type definitions for PPC 8XX processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for PPC8XX processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for PPC8XX processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for PPC8XX processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for PPC8XX processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for PPC8XX processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for PPC8XX processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_SH4_7750 +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER /**< SH7750 platform byte ordering is big-endian. */ + +/** @name CPU/compiler-dependent primitive data type definitions for SH7750 processor series of the SH-4 processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for SH7750 SH-4 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for SH7750 SH-4 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for SH7750 SH-4 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for SH7750 SH-4 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for SH7750 SH-4 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for SH7750 SH-4 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_ARM7_LEND +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER + +/** @name little-endian CPU/compiler-dependent primitive data type definitions for the ARM7 processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for ARM7 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for ARM7 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for ARM7 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for ARM7 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for ARM7 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for ARM7 processor. */ + +typedef void *OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_ARM7_BEND +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER +/** @name big-endian CPU/compiler-dependent primitive data type definitions for the ARM7 processor family + * @{ + */ +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for ARM7 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for ARM7 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for ARM7 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for ARM7 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for ARM7 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for ARM7 processor. */ + +typedef void *OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_GDM1202 +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER + +typedef signed char OI_INT8; /**< 8-bit signed integer. */ +typedef signed short OI_INT16; /**< 16-bit signed integer. */ +typedef signed long OI_INT32; /**< 32-bit signed integer. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_ARC_LEND + +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER + +/** @name CPU/compiler-dependent primitive data type definitions for ARC processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for ARC processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for ARC processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for ARC processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for ARC processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for ARC processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for ARC processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_ARC_BEND + +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER + +/** @name CPU/compiler-dependent primitive data type definitions for ARC processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for ARC processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for ARC processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for ARC processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for ARC processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for ARC processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for ARC processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_M30833F + +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER + +/** @name CPU/compiler-dependent primitive data type definitions for Mitsubishi M308 processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for M308 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for M308 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for M308 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for M308 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for M308 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for M308 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_CR16C + +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER + +/** @name CPU/compiler-dependent primitive data type definitions for National Semicnductor processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for CR16C processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for CR16C processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for CR16C processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for CR16C processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for CR16C processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for CR16C processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_M64111 + +#define OI_CPU_BYTE_ORDER OI_BIG_ENDIAN_BYTE_ORDER + +/** @name CPU/compiler-dependent primitive data type definitions for Renesas M32R processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for M64111 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for M64111 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for M64111 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for M64111 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for M64111 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for M64111 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ +#endif + +/*********************************************************************************/ + +#if OI_CPU_TYPE==OI_CPU_ARMV5_LEND +#define OI_CPU_BYTE_ORDER OI_LITTLE_ENDIAN_BYTE_ORDER + +/** @name little-endian CPU/compiler-dependent primitive data type definitions for the ARM7 processor family + * @{ + */ + +typedef signed char OI_INT8; /**< 8-bit signed integer values use native signed character data type for ARM7 processor. */ +typedef signed short OI_INT16; /**< 16-bit signed integer values use native signed short integer data type for ARM7 processor. */ +typedef signed long OI_INT32; /**< 32-bit signed integer values use native signed long integer data type for ARM7 processor. */ +typedef unsigned char OI_UINT8; /**< 8-bit unsigned integer values use native unsigned character data type for ARM7 processor. */ +typedef unsigned short OI_UINT16; /**< 16-bit unsigned integer values use native unsigned short integer data type for ARM7 processor. */ +typedef unsigned long OI_UINT32; /**< 32-bit unsigned integer values use native unsigned long integer data type for ARM7 processor. */ + +typedef OI_UINT32 OI_ELEMENT_UNION; /**< Type for first element of a union to support all data types up to pointer width. */ + +/**@}*/ + +#endif + +/*********************************************************************************/ + + +#ifndef OI_CPU_BYTE_ORDER +#error "Byte order (endian-ness) not defined" +#endif + + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +/*********************************************************************************/ +#endif /* _OI_CPU_DEP_H */ diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_modules.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_modules.h new file mode 100644 index 0000000000..7784212ad2 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_modules.h @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_MODULES_H +#define _OI_MODULES_H +/** + * @file + * + * Enumeration type defining the inidivual stack components. + * + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * This enumeration lists constants for referencing the components of + * the BLUEmagic 3.0 protocol stack, profiles, and other functionalities. + * + * In order to distinguish types of modules, items are grouped with markers to + * delineate start and end of the groups + * + * The module type is used for various purposes: + * identification in debug print statements + * access to initialization flags + * access to the configuration table + */ + +typedef enum { + /* profiles and protocols --> Updates to oi_debug.c and oi_config_table.c */ + + /* XX --> Keep Enum values up-to-date! */ + OI_MODULE_AT, /**< 00 AT command processing */ + OI_MODULE_A2DP, /**< 01 Advanced Audio Distribution Profile */ + OI_MODULE_AVCTP, /**< 02 Audio-Visual Control Transport Profile */ + OI_MODULE_AVDTP, /**< 03 Audio-Visual Distribution Protocol */ + OI_MODULE_AVRCP, /**< 04 Audio-Visual Remote Control Profile */ + OI_MODULE_BIP_CLI, /**< 05 Basic Imaging Profile protocol client */ + OI_MODULE_BIP_SRV, /**< 06 Basic Imaging Profile protocol server */ + OI_MODULE_BNEP, /**< 07 Bluetooth Network Encapsulation Protocol */ + OI_MODULE_BPP_SENDER, /**< 08 Basic Printing Profile */ + OI_MODULE_BPP_PRINTER, /**< 09 Basic Printing Profile */ + OI_MODULE_CTP, /**< 10 Cordless Telephony Profile */ + OI_MODULE_DUN, /**< 11 Dial-Up Networking Profile */ + OI_MODULE_FAX, /**< 12 Fax Profile */ + OI_MODULE_FTP_CLI, /**< 13 File Transfer Profile protocol client */ + OI_MODULE_FTP_SRV, /**< 14 File Transfer Profile protocol server */ + OI_MODULE_HANDSFREE, /**< 15 Hands-Free Profile */ + OI_MODULE_HANDSFREE_AG, /**< 16 Hands-Free Profile */ + OI_MODULE_HCRP_CLI, /**< 17 Hardcopy Cable Replacement Profile */ + OI_MODULE_HCRP_SRV, /**< 18 Hardcopy Cable Replacement Profile */ + OI_MODULE_HEADSET, /**< 19 Headset Profile */ + OI_MODULE_HEADSET_AG, /**< 20 Headset Profile */ + OI_MODULE_HID, /**< 21 Human Interface Device profile */ + OI_MODULE_INTERCOM, /**< 22 Intercom Profile */ + OI_MODULE_OBEX_CLI, /**< 23 OBEX protocol client, Generic Object Exchange Profile */ + OI_MODULE_OBEX_SRV, /**< 24 OBEX protocol server, Generic Object Exchange Profile */ + OI_MODULE_OPP_CLI, /**< 25 Object Push Profile protocol client */ + OI_MODULE_OPP_SRV, /**< 26 Object Push Profile protocol server */ + OI_MODULE_PAN, /**< 27 PAN profile */ + OI_MODULE_PBAP_CLI, /**< 28 Phonebook Access Profile client */ + OI_MODULE_PBAP_SRV, /**< 29 Phonebook Access Profile server */ + OI_MODULE_SAP_CLI, /**< 30 SIM Access Profile */ + OI_MODULE_SAP_SRV, /**< 31 SIM Access Profile */ + OI_MODULE_SPP, /**< 32 Serial Port Profile */ + OI_MODULE_SYNC_CLI, /**< 33 Synchronization Profile */ + OI_MODULE_SYNC_SRV, /**< 34 Synchronization Profile */ + OI_MODULE_SYNC_CMD_CLI, /**< 35 Synchronization Profile */ + OI_MODULE_SYNC_CMD_SRV, /**< 36 Synchronization Profile */ + OI_MODULE_SYNCML, /**< 37 SyncML Profile */ + OI_MODULE_TCS, /**< 38 TCS Binary */ + OI_MODULE_VDP, /**< 39 Video Distribution Profile */ + + /* corestack components --> Updates to oi_debug.c and oi_config_table.c */ + + OI_MODULE_COMMON_CONFIG, /**< 40 Common configuration, module has no meaning other than for config struct */ + OI_MODULE_CMDCHAIN, /**< 41 Command chaining utility */ + OI_MODULE_DISPATCH, /**< 42 Dispatcher */ + OI_MODULE_DATAELEM, /**< 43 Data Elements, marshaller */ + OI_MODULE_DEVMGR, /**< 44 Device Manager */ + OI_MODULE_DEVMGR_MODES, /**< 45 Device Manager connectability/discoverability modes */ + OI_MODULE_HCI, /**< 46 Host Controller Interface command layer */ + OI_MODULE_L2CAP, /**< 47 L2CAP */ + OI_MODULE_MEMMGR, /**< 48 modules that do memory management */ + OI_MODULE_POLICYMGR, /**< 49 Policy Manager */ + OI_MODULE_RFCOMM, /**< 50 RFCOMM */ + OI_MODULE_RFCOMM_SD, /**< 51 RFCOMM Service discovery */ + OI_MODULE_SDP_CLI, /**< 52 Service Discovery Protocol client */ + OI_MODULE_SDP_SRV, /**< 53 Service Discovery Protocol server */ + OI_MODULE_SDPDB, /**< 54 Service Discovery Protocol database */ + OI_MODULE_SECMGR, /**< 55 Security Manager */ + OI_MODULE_SNIFFLOG, /**< 56 sniff log */ + OI_MODULE_SUPPORT, /**< 57 support functions, including CThru Dispatcher, time functions, and stack initialization */ + OI_MODULE_TRANSPORT, /**< 58 transport layer between HCI command layer and driver */ + OI_MODULE_TEST, /**< 59 used to debug output from internal test programs */ + OI_MODULE_XML, /**< 60 XML/CSS parser */ + + OI_MODULE_DI, /**< 61 Device Identification Profile */ + + // bhapi components --> Updates to oi_debug.c + + OI_MODULE_BHAPI, /**< 62 BLUEmagic Host API generic */ + OI_MODULE_BHCLI, /**< 63 BLUEmagic Host API client side */ + OI_MODULE_BHSRV, /**< 64 BLUEmagic Host API server side */ + OI_MODULE_MSGQ, /**< 65 module that handles message queuing */ + OI_MODULE_BHAPI_TRANSPORT, /**< 66 module that handles message queuing */ + OI_MODULE_BLST_SRV, /**< 67 module that provides server side BHAPI Lightweight Serial Transport */ + OI_MODULE_BLST_CLI, /**< 68 module that provides client side BHAPI Lightweight Serial Transport */ + + // OEM files --> Updates to oi_debug.c + OI_MODULE_OEM, /**< 69 Application Memory allocation */ + + // Application glue --> Updates to oi_debug.c + OI_MODULE_APP, /**< 70 Application Memory allocation */ + + /* various pieces of code depend on these last 2 elements occuring in a specific order: + OI_MODULE_ALL must be the 2nd to last element + OI_MODULE_UNKNOWN must be the last element + */ + OI_MODULE_ALL, /**< 71 special value identifying all modules - used for control of debug print statements */ + OI_MODULE_UNKNOWN /**< 72 special value - used for debug print statements */ +} OI_MODULE; + +/** + * This constant is the number of actual modules in the list. ALL and UNKNOWN are + * special values that are not actually modules. + * Used for debug print and memmgr profiling + */ +#define OI_NUM_MODULES OI_MODULE_ALL + + +/** + * This constant is the number of profile and core components. It is used to size + * the initialization and configuration tables. + */ +#define OI_NUM_STACK_MODULES OI_MODULE_BHAPI + + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* _OI_MODULES_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_osinterface.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_osinterface.h new file mode 100644 index 0000000000..7868041900 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_osinterface.h @@ -0,0 +1,197 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_OSINTERFACE_H +#define _OI_OSINTERFACE_H +/** + @file + * This file provides the platform-independent interface for functions for which + * implementation is platform-specific. + * + * The functions in this header file define the operating system or hardware + * services needed by the BLUEmagic 3.0 protocol stack. The + * actual implementation of these services is platform-dependent. + * + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#include "oi_stddefs.h" +#include "oi_time.h" +#include "oi_status.h" +#include "oi_modules.h" + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Terminates execution. + * + * @param reason Reason for termination + */ +void OI_FatalError(OI_STATUS reason); + +/** + * This function logs an error. + * + * When built for release mode, BLUEmagic 3 errors are logged to + * this function. (in debug mode, errors are logged via + * OI_Print()). + * + * @param module Module in which the error was detected (see + * oi_modules.h) + * @param lineno Line number of the C file OI_SLOG_ERROR called + * @param status Status code associated with the error event + */ +void OI_LogError(OI_MODULE module, OI_INT lineno, OI_STATUS status); + +/** + * This function initializes the debug code handling. + * + * When built for debug mode, this function performs platform + * dependent initialization to handle message codes passed in + * via OI_SetMsgCode(). + */ +void OI_InitDebugCodeHandler(void); + + +/** + * This function reads the time from the real time clock. + * + * All timing in BM3 is relative, typically a granularity + * of 5 or 10 msecs is adequate. + * + * @param[out] now Pointer to the buffer to which the current + * time will be returned + */ +void OI_Time_Now(OI_TIME *now); + +/** + * This function causes the current thread to sleep for the + * specified amount of time. This function must be called + * without the stack access token. + * + * @note BM3 corestack and profiles never suspend and never call + * OI_Sleep. The use of OI_Sleep is limited to applications and + * platform-specific code. + * + * If your port and applications never use OI_Sleep, this function can be left unimplemented. + * + * @param milliseconds Number of milliseconds to sleep + */ +void OI_Sleep(OI_UINT32 milliseconds); + + +/** + * Defines for message type codes. + */ +#define OI_MSG_CODE_APPLICATION 0 /**< Application output */ +#define OI_MSG_CODE_ERROR 1 /**< Error message output */ +#define OI_MSG_CODE_WARNING 2 /**< Warning message output */ +#define OI_MSG_CODE_TRACE 3 /**< User API function trace output */ +#define OI_MSG_CODE_PRINT1 4 /**< Catagory 1 debug print output */ +#define OI_MSG_CODE_PRINT2 5 /**< Catagory 2 debug print output */ +#define OI_MSG_CODE_HEADER 6 /**< Error/Debug output header */ + +/** + * This function is used to indicate the type of text being output with + * OI_Print(). For the Linux and Win32 platforms, it will set + * the color of the text. Other possible uses could be to insert + * HTML style tags, add some other message type indication, or + * be completely ignored altogether. + * + * @param code OI_MSG_CODE_* indicating setting the message type. + */ +void OI_SetMsgCode(OI_UINT8 code); + +/** + * All output from OI_Printf() and all debug output is sent to OI_Print. + * Typically, if the platform has a console, OI_Print() is sent to stdout. + * Embedded platforms typically send OI_Print() output to a serial port. + * + * @param str String to print + */ +void OI_Print(OI_CHAR const *str); + +/** + * In cases where OI_Print() is sending output to a logfile in addition to console, + * it is desirable to also put console input into the logfile. + * This function can be called by the console input process. + * + * @note This is an optional API which is strictly + * between the platform-specific stack_console and osinterface + * modules. This API need only be implemented on those + * platforms where is serves a useful purpose, e.g., win32. + * + * @param str Console input string + */ + +void OI_Print_ConsoleInput(OI_CHAR const *str); + +/** + * This function computes the CRC16 of the program image. + */ +OI_UINT16 OI_ProgramImageCRC16(void); + +/** + * Writes an integer to stdout in hex. This macro is intended + * for selective use when debugging in small memory + * configurations or other times when it is not possible to use + * OI_DBGPRINT. + * + * @param n the integer to print + */ + +#define OI_Print_Int(n) \ +{ \ + static const OI_CHAR _digits[] = "0123456789ABCDEF"; \ + OI_CHAR _buf[9]; \ + OI_CHAR *_str = &_buf[8]; \ + OI_UINT32 _i = n; \ + *_str = 0; \ + do { *(--_str) = _digits[(_i & 0xF)]; _i >>= 4; } while (_i); \ + OI_Print(_str); \ +} + +/** + * Application Dynamic Memory allocation. + * + * These APIs are provided for application use on those + * platforms which have no dynamic memory support. Memory is + * allocated from the pool-based heap managed by the stack's + * internal memory manager. + */ +void *OI_APP_Malloc(OI_INT32 size); +void OI_APP_Free(void *ptr); + +/*****************************************************************************/ +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* _OI_OSINTERFACE_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_status.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_status.h new file mode 100644 index 0000000000..8c392a292d --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_status.h @@ -0,0 +1,579 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_STATUS_H +#define _OI_STATUS_H +/** + * @file + * This file contains status codes for BLUEmagic 3.0 software. + */ + +#include "oi_stddefs.h" + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** test it **/ + +/** + * OI_STATUS must fit in 16 bits, so status codes can range from 0 to 66535, inclusive. + */ + +typedef enum { + OI_STATUS_SUCCESS = 0, /**< function call succeeded alias for #OI_OK */ + OI_OK = 0, /**< function call succeeded alias for #OI_STATUS_SUCCESS */ + OI_STATUS_INVALID_PARAMETERS = 101, /**< invalid function input parameters */ + OI_STATUS_NOT_IMPLEMENTED = 102, /**< attempt to use an unimplemented function */ + OI_STATUS_NOT_INITIALIZED = 103, /**< data not initialized */ + OI_STATUS_NO_RESOURCES = 104, /**< generic resource allocation failure status */ + OI_STATUS_INTERNAL_ERROR = 105, /**< internal inconsistency */ + OI_STATUS_OUT_OF_MEMORY = 106, /**< generally, OI_Malloc failed */ + OI_ILLEGAL_REENTRANT_CALL = 107, /**< violation of non-reentrant module policy */ + OI_STATUS_INITIALIZATION_FAILED = 108, /**< module initialization failed */ + OI_STATUS_INITIALIZATION_PENDING = 109, /**< inititialization not yet complete */ + OI_STATUS_NO_SCO_SUPPORT = 110, /**< SCO operation rejected; system not configured for SCO */ + OI_STATUS_OUT_OF_STATIC_MEMORY = 111, /**< static malloc failed */ + OI_TIMEOUT = 112, /**< generic timeout */ + OI_OS_ERROR = 113, /**< some operating system error */ + OI_FAIL = 114, /**< generic failure */ + OI_STRING_FORMAT_ERROR = 115, /**< error in VarString formatting string */ + OI_STATUS_PENDING = 116, /**< The operation is pending. */ + OI_STATUS_INVALID_COMMAND = 117, /**< The command was invalid. */ + OI_BUSY_FAIL = 118, /**< command rejected due to busy */ + OI_STATUS_ALREADY_REGISTERED = 119, /**< The registration has already been performed. */ + OI_STATUS_NOT_FOUND = 120, /**< The referenced resource was not found. */ + OI_STATUS_NOT_REGISTERED = 121, /**< not registered */ + OI_STATUS_NOT_CONNECTED = 122, /**< not connected */ + OI_CALLBACK_FUNCTION_REQUIRED = 123, /**< A callback function parameter was required. */ + OI_STATUS_MBUF_OVERFLOW = 124, /**< There is no room to add another buffer to an mbuf. */ + OI_STATUS_MBUF_UNDERFLOW = 125, /**< There was an attempt to pull too many bytes from an mbuf. */ + OI_STATUS_CONNECTION_EXISTS = 126, /**< connection exists */ + OI_STATUS_NOT_CONFIGURED = 127, /**< module not configured */ + OI_LOWER_STACK_ERROR = 128, /**< An error was reported by lower stack API. This is used for embedded platforms. */ + OI_STATUS_RESET_IN_PROGRESS = 129, /**< Request failed/rejected because we're busy resetting. */ + OI_STATUS_ACCESS_DENIED = 130, /**< Generic access denied error. */ + OI_STATUS_DATA_ERROR = 131, /**< Generic data error. */ + OI_STATUS_INVALID_ROLE = 132, /**< The requested role was invalid. */ + OI_STATUS_ALREADY_CONNECTED = 133, /**< The requested connection is already established. */ + OI_STATUS_PARSE_ERROR = 134, /**< Parse error */ + OI_STATUS_END_OF_FILE = 135, /**< End of file */ + OI_STATUS_READ_ERROR = 136, /**< Generic read error */ + OI_STATUS_WRITE_ERROR = 137, /**< Generic write error */ + OI_STATUS_NEGOTIATION_FAILURE = 138, /**< Error in negotiation */ + OI_STATUS_READ_IN_PROGRESS = 139, /**< A read is already in progress */ + OI_STATUS_ALREADY_INITIALIZED = 140, /**< Initialization has already been done */ + OI_STATUS_STILL_CONNECTED = 141, /**< The service cannot be shutdown because there are still active connections. */ + OI_STATUS_MTU_EXCEEDED = 142, /**< The packet is too big */ + OI_STATUS_LINK_TERMINATED = 143, /**< The link was terminated */ + OI_STATUS_PIN_CODE_TOO_LONG = 144, /**< Application gave us a pin code that is too long */ + OI_STATUS_STILL_REGISTERED = 145, /**< The service cannot be shutdown because there are still active registrations. */ + OI_STATUS_SPEC_VIOLATION = 146, /**< Some application behavior contrary to BT specifications */ + + + OI_STATUS_PSM_ALREADY_REGISTERED = 402, /**< L2CAP: The specified PSM has already been registered. */ + OI_STATUS_INVALID_CID = 403, /**< L2CAP: CID is invalid or no longer valid (connection terminated) */ + OI_STATUS_CID_NOT_FOUND = 404, /**< L2CAP: CID does not represent a current connection */ + OI_STATUS_CHANNEL_NOT_FOUND = 406, /**< L2CAP: CID does not represent a current connection */ + OI_STATUS_PSM_NOT_FOUND = 407, /**< L2CAP: PSM not found */ + OI_STATUS_INVALID_STATE = 408, /**< L2CAP: invalid state */ + OI_STATUS_WRITE_IN_PROGRESS = 410, /**< L2CAP: write in progress */ + OI_STATUS_INVALID_PACKET = 411, /**< L2CAP: invalid packet */ + OI_STATUS_SEND_COMPLETE = 412, /**< L2CAP: send is complete */ + OI_STATUS_INVALID_HANDLE = 414, /**< L2CAP: handle is invalid */ + OI_STATUS_GROUP_FULL = 418, /**< L2CAP: No more members can be added to the specified group. */ + OI_STATUS_DEVICE_ALREADY_IN_GROUP = 423, /**< L2CAP: The device already exists in the group. */ + OI_STATUS_DUPLICATE_GROUP = 425, /**< L2CAP: attempt to add more than one group */ + OI_STATUS_EMPTY_GROUP = 426, /**< L2CAP: group is empty */ + OI_STATUS_PACKET_NOT_FOUND = 427, /**< L2CAP: packet not found */ + OI_STATUS_BUFFER_TOO_SMALL = 428, /**< L2CAP: The buffer size is too small. */ + OI_STATUS_IDENTIFIER_NOT_FOUND = 429, /**< L2CAP: identifier not found */ + + OI_L2CAP_DISCONNECT_LOWER_LAYER = 430, /**< L2CAP: The lower level forced a disconnect. */ + OI_L2CAP_DISCONNECT_REMOTE_REQUEST = 431, /**< L2CAP: The remote device requested a disconnect. */ + OI_L2CAP_GROUP_ADD_CONNECT_FAIL = 433, /**< L2CAP: Group add connect faiL */ + OI_L2CAP_GROUP_REMOVE_FAILURE = 434, /**< L2CAP: Group remove failure */ + OI_L2CAP_DATA_WRITE_ERROR_LINK_TERM = 435, /**< L2CAP: Data write error LINK_TERM */ + OI_L2CAP_DISCONNECT_LOCAL_REQUEST = 436, /**< L2CAP: Disconnect local request */ + + OI_L2CAP_CONNECT_TIMEOUT = 437, /**< L2CAP: Connect timeout */ + OI_L2CAP_DISCONNECT_TIMEOUT = 439, /**< L2CAP: Disconnect timeout */ + OI_L2CAP_PING_TIMEOUT = 440, /**< L2CAP: Ping timeout */ + OI_L2CAP_GET_INFO_TIMEOUT = 441, /**< L2CAP: Get info timeout */ + OI_L2CAP_INVALID_ADDRESS = 444, /**< L2CAP: Invalid address */ + OI_L2CAP_CMD_REJECT_RCVD = 445, /**< L2CAP: remote sent us 'command reject' response */ + + OI_L2CAP_CONNECT_BASE = 450, /**< L2CAP: Connect base */ + OI_L2CAP_CONNECT_PENDING = 451, /**< L2CAP: Connect pending */ + OI_L2CAP_CONNECT_REFUSED_INVALID_PSM = 452, /**< L2CAP: Connect refused invalid PSM */ + OI_L2CAP_CONNECT_REFUSED_SECURITY = 453, /**< L2CAP: Connect refused security */ + OI_L2CAP_CONNECT_REFUSED_NO_RESOURCES = 454, /**< L2CAP: Connect refused no resources */ + + OI_L2CAP_CONFIG_BASE = 460, /**< L2CAP: Config base */ + OI_L2CAP_CONFIG_FAIL_INVALID_PARAMETERS = 461, /**< L2CAP: Config fail invalid parameters */ + OI_L2CAP_CONFIG_FAIL_NO_REASON = 462, /**< L2CAP: Config fail no reason */ + OI_L2CAP_CONFIG_FAIL_UNKNOWN_OPTIONS = 463, /**< L2CAP: Config fail unknown options */ + + OI_L2CAP_GET_INFO_BASE = 470, /**< L2CAP: Get info base */ + OI_L2CAP_GET_INFO_NOT_SUPPORTED = 471, /**< L2CAP: Get info not supported */ + OI_L2CAP_MTU_EXCEEDED = 472, /**< L2CAP: The MTU of the channel was exceeded */ + OI_L2CAP_INVALID_PSM = 482, /**< L2CAP: Invalid PSM */ + OI_L2CAP_INVALID_MTU = 483, /**< L2CAP: Invalid MTU */ + OI_L2CAP_INVALID_FLUSHTO = 484, /**< L2CAP: Invalid flush timeout */ + + OI_HCI_NO_SUCH_CONNECTION = 601, /**< HCI: caller specified a non-existent connection handle */ + OI_HCI_CB_LIST_FULL = 603, /**< HCI: callback list is full, cannot attempt to send command */ + OI_HCI_EVENT_UNDERRUN = 605, /**< HCI: parsing event packet, premature end-of-parameters */ + OI_HCI_UNKNOWN_EVENT_CODE = 607, /**< HCI: event received - event code is unknown */ + OI_HCI_BAD_EVENT_PARM_LEN = 608, /**< HCI: event - parameter length is incorrect */ + OI_HCI_CMD_QUEUE_FULL = 611, /**< HCI: command queue is full */ + OI_HCI_SHORT_EVENT = 612, /**< HCI: event received, missing event code and/or parm len */ + OI_HCI_TRANSMIT_NOT_READY = 613, /**< HCI: ACL/SCO transmit request failed - busy or no buffers available */ + OI_HCI_ORPHAN_SENT_EVENT = 614, /**< HCI: got spurious 'sent' event from transport layer */ + OI_HCI_CMD_TABLE_ERROR = 615, /**< HCI: inconsistency in the internal command table */ + OI_HCI_UNKNOWN_CMD_ID = 616, /**< HCI: HciApi Command - unknown command id */ + OI_HCI_UNEXPECTED_EVENT = 619, /**< HCI: event received which only occurs in response to our cmd */ + OI_HCI_EVENT_TABLE_ERROR = 620, /**< HCI: inconsistency in the internal event table */ + OI_HCI_EXPECTED_EVENT_TIMOUT = 621, /**< HCI: timed out waiting for an expected event */ + OI_HCI_NO_CMD_DESC_FOR_OPCODE = 622, /**< HCI: event opcode is not known */ + OI_HCI_INVALID_OPCODE_ERROR = 623, /**< HCI: command opcode is invalid */ + OI_HCI_FLOW_CONTROL_DISABLED = 624, /**< HCI: can not use host flow control APIs if disabled in configuration */ + OI_HCI_TX_COMPLETE = 625, /**< HCI: packet delivery to Host Controler complete */ + OI_HCI_TX_ERROR = 626, /**< HCI: failed to deliver packet to Host Controler */ + OI_HCI_DEVICE_NOT_INITIALIZED = 627, /**< HCI: commands from upper layers disallowed until device is up and running */ + OI_HCI_UNSUPPORTED_COMMAND = 628, /**< HCI: command requested is not supported by local device */ + OI_HCI_PASSTHROUGH_ERROR = 629, /**< HCI: Error processing passthrough command */ + OI_HCI_PASSTHROUGH_ALREADY_SET = 630, /**< HCI: Passthrough mode already enabled */ + OI_HCI_RESET_FAILURE = 631, /**< HCI: failed to reset the device/baseband */ + OI_HCI_TRANSPORT_RESET = 632, /**< HCI: some operation failed because of a reset in the transport */ + OI_HCIERR_HCIIFC_INIT_FAILURE = 633, /**< HCI: failed to initialize transport layer interface */ + + OI_HCIERR_FIRST_ERROR_VALUE = 701, /**< marker for first HCI protocol error */ + OI_HCIERR_UNKNOWN_HCI_COMMAND = 701, /**< HCI: protocol error 0x01 */ + OI_HCIERR_NO_CONNECTION = 702, /**< HCI: protocol error 0x02 */ + OI_HCIERR_HARDWARE_FAILURE = 703, /**< HCI: protocol error 0x03 */ + OI_HCIERR_PAGE_TIMEOUT = 704, /**< HCI: protocol error 0x04 */ + OI_HCIERR_AUTHENTICATION_FAILURE = 705, /**< HCI: protocol error 0x05 */ + OI_HCIERR_KEY_MISSING = 706, /**< HCI: protocol error 0x06 */ + OI_HCIERR_MEMORY_FULL = 707, /**< HCI: protocol error 0x07 */ + OI_HCIERR_CONNECTION_TIMEOUT = 708, /**< HCI: protocol error 0x08 */ + OI_HCIERR_MAX_NUM_OF_CONNECTIONS = 709, /**< HCI: protocol error 0x09 */ + OI_HCIERR_MAX_NUM_OF_SCO_CONNECTIONS = 710, /**< HCI: protocol error 0x0A */ + OI_HCIERR_ACL_CONNECTION_ALREADY_EXISTS = 711, /**< HCI: protocol error 0x0B */ + OI_HCIERR_COMMAND_DISALLOWED = 712, /**< HCI: protocol error 0x0C */ + OI_HCIERR_HOST_REJECTED_RESOURCES = 713, /**< HCI: protocol error 0x0D */ + OI_HCIERR_HOST_REJECTED_SECURITY = 714, /**< HCI: protocol error 0x0E */ + OI_HCIERR_HOST_REJECTED_PERSONAL_DEVICE = 715, /**< HCI: protocol error 0x0F */ + OI_HCIERR_HOST_TIMEOUT = 716, /**< HCI: protocol error 0x10 */ + OI_HCIERR_UNSUPPORTED = 717, /**< HCI: protocol error 0x11 */ + OI_HCIERR_INVALID_PARAMETERS = 718, /**< HCI: protocol error 0x12 */ + OI_HCIERR_OTHER_END_USER_DISCONNECT = 719, /**< HCI: protocol error 0x13 */ + OI_HCIERR_OTHER_END_LOW_RESOURCES = 720, /**< HCI: protocol error 0x14 */ + OI_HCIERR_OTHER_END_POWERING_OFF = 721, /**< HCI: protocol error 0x15 */ + OI_HCIERR_CONNECTION_TERMINATED_LOCALLY = 722, /**< HCI: protocol error 0x16 */ + OI_HCIERR_REPEATED_ATTEMPTS = 723, /**< HCI: protocol error 0x17 */ + OI_HCIERR_PAIRING_NOT_ALLOWED = 724, /**< HCI: protocol error 0x18 */ + OI_HCIERR_UNKNOWN_LMP_PDU = 725, /**< HCI: protocol error 0x19 */ + OI_HCIERR_UNSUPPORTED_REMOTE_FEATURE = 726, /**< HCI: protocol error 0x1A */ + OI_HCIERR_SCO_OFFSET_REJECTED = 727, /**< HCI: protocol error 0x1B */ + OI_HCIERR_SCO_INTERVAL_REJECTED = 728, /**< HCI: protocol error 0x1C */ + OI_HCIERR_SCO_AIR_MODE_REJECTED = 729, /**< HCI: protocol error 0x1D */ + OI_HCIERR_INVALID_LMP_PARMS = 730, /**< HCI: protocol error 0x1E */ + OI_HCIERR_UNSPECIFIED_ERROR = 731, /**< HCI: protocol error 0x1F */ + OI_HCIERR_UNSUPPORTED_LMP_PARAMETERS = 732, /**< HCI: protocol error 0x20 */ + OI_HCIERR_ROLE_CHANGE_NOT_ALLOWED = 733, /**< HCI: protocol error 0x21 */ + OI_HCIERR_LMP_RESPONSE_TIMEOUT = 734, /**< HCI: protocol error 0x22 */ + OI_HCIERR_LMP_ERROR_TRANS_COLLISION = 735, /**< HCI: protocol error 0x23 */ + OI_HCIERR_LMP_PDU_NOT_ALLOWED = 736, /**< HCI: protocol error 0x24 */ + OI_HCIERR_ENCRYPTION_MODE_NOT_ACCEPTABLE = 737, /**< HCI: protocol error 0x25 */ + OI_HCIERR_UNIT_KEY_USED = 738, /**< HCI: protocol error 0x26 */ + OI_HCIERR_QOS_NOT_SUPPORTED = 739, /**< HCI: protocol error 0x27 */ + OI_HCIERR_INSTANT_PASSED = 740, /**< HCI: protocol error 0x28 */ + OI_HCIERR_UNIT_KEY_PAIRING_UNSUPPORTED = 741, /**< HCI: protocol error 0x29 */ + OI_HCIERR_DIFFERENT_TRANS_COLLISION = 742, /**< HCI: protocol error 0x2A */ + OI_HCIERR_RESERVED_2B = 743, /**< HCI: protocol error 0x2B */ + OI_HCIERR_QOS_UNACCEPTABLE_PARAMETER = 744, /**< HCI: protocol error 0x2C */ + OI_HCIERR_QOS_REJECTED = 745, /**< HCI: protocol error 0x2D */ + OI_HCIERR_CHANNEL_CLASSIFICATION_NS = 746, /**< HCI: protocol error 0x2E */ + OI_HCIERR_INSUFFICIENT_SECURITY = 747, /**< HCI: protocol error 0x2F */ + OI_HCIERR_PARM_OUT_OF_MANDATORY_RANGE = 748, /**< HCI: protocol error 0x30 */ + OI_HCIERR_RESERVED_31 = 749, /**< HCI: protocol error 0x31 */ + OI_HCIERR_ROLE_SWITCH_PENDING = 750, /**< HCI: protocol error 0x32 */ + OI_HCIERR_RESERVED_33 = 751, /**< HCI: protocol error 0x33 */ + OI_HCIERR_RESERVED_SLOT_VIOLATION = 752, /**< HCI: protocol error 0x34 */ + OI_HCIERR_ROLE_SWITCH_FAILED = 753, /**< HCI: protocol error 0x35 */ + OI_HCIERR_EIR_TOO_LARGE = 754, /**< HCI: protocol error 0x36 */ + OI_HCIERR_SSP_NOT_SUPPORTED_BY_HOST = 755, /**< HCI: protocol error 0x37 */ + OI_HCIERR_HOST_BUSY_PAIRING = 756, /**< HCI: protocol error 0x38 */ + + OI_HCIERR_UNKNOWN_ERROR = 757, /**< HCI: unknown error code */ + OI_HCIERR_LAST_ERROR_VALUE = 757, /**< marker for last HCI protocol error */ + + OI_SDP_SPEC_ERROR = 800, /**< SDP: Base error status for mapping OI_STATUS codes to SDP errors */ + OI_SDP_INVALID_SERVICE_RECORD_HANDLE = (OI_SDP_SPEC_ERROR + 2), /**< SDP: protocol error Invalid Service Record Handle */ + OI_SDP_INVALID_REQUEST_SYNTAX = (OI_SDP_SPEC_ERROR + 3), /**< SDP: protocol error Invalid Request Syntax */ + OI_SDP_INVALID_PDU_SIZE = (OI_SDP_SPEC_ERROR + 4), /**< SDP: protocol error Invalid PDU Size */ + OI_SDP_INVALID_CONTINUATION_STATE = (OI_SDP_SPEC_ERROR + 5), /**< SDP: protocol error Invalid Continuation State */ + OI_SDP_INSUFFICIENT_RESOURCES = (OI_SDP_SPEC_ERROR + 6), /**< SDP: protocol error Insufficient Resources */ + OI_SDP_ERROR = 807, /**< SDP: server returned an error code */ + OI_SDP_CORRUPT_DATA_ELEMENT = 808, /**< SDP: Invalid or corrupt data element representation */ + OI_SDP_SERVER_NOT_CONNECTED = 810, /**< SDP: Attempt to disconnect from an unconnected server */ + OI_SDP_ACCESS_DENIED = 811, /**< SDP: Server denied access to server */ + OI_SDP_ATTRIBUTES_OUT_OF_ORDER = 812, /**< SDP: Attributes in attribute list not in ascending order */ + OI_SDP_DEVICE_DOES_NOT_SUPPORT_SDP = 813, /**< SDP: Tried to connect to a device that does not support SDP */ + OI_SDP_NO_MORE_DATA = 815, /**< SDP: Server does not have more continuation data */ + OI_SDP_REQUEST_PARAMS_TOO_LONG = 816, /**< SDP: Parameters for a request exceed the L2CAP buffer size */ + OI_SDP_REQUEST_PENDING = 817, /**< SDP: Cannot make a request when another request is being processed */ + OI_SDP_SERVER_CONNECT_FAILED = 819, /**< SDP: Failed attempt to connect to an SDP server */ + OI_SDP_SERVER_TOO_MANY_CONNECTIONS = 821, /**< SDP: Exceeded maximum number of simultaneous server connections */ + OI_SDP_NO_MATCHING_SERVICE_RECORD = 823, /**< SDP: No service record matched the UUID list */ + OI_SDP_PARTIAL_RESPONSE = 824, /**< SDP: Internal use only */ + OI_SDP_ILLEGAL_ARGUMENT = 825, /**< SDP: Illegal argument passed to an SDP function */ + OI_SDP_ATTRIBUTE_NOT_FOUND = 826, /**< SDP: A requested attribute was not found in a service record */ + OI_SDP_DATABASE_OUT_OF_RESOURCES = 827, /**< SDP: server database is out of memory */ + OI_SDP_SHORT_PDU = 829, /**< SDP: Not enough bytes in the packet */ + OI_SDP_TRANSACTION_ID_MISMATCH = 830, /**< SDP: Transaction Id was not as expected */ + OI_SDP_UNEXPECTED_RESPONSE_PDU_ID = 831, /**< SDP: Did not expect this response PDU */ + OI_SDP_REQUEST_TIMEOUT = 832, /**< SDP: Did not get a response within the timeout period */ + OI_SDP_INVALID_RESPONSE_SYNTAX = 833, /**< SDP: Response is not correctly formatted */ + OI_SDP_CONNECTION_TIMEOUT = 834, /**< SDP: Connection attempt timed out at a lower layer */ + OI_SDP_RESPONSE_DATA_ERROR = 835, /**< SDP: Response to a service request appears to be corrupt */ + OI_SDP_TOO_MANY_ATTRIBUTE_BYTES = 836, /**< SDP: Response contained more bytes than requested. */ + OI_SDP_TOO_MANY_SERVICE_RECORDS = 837, /**< SDP: Response contained more service records than requested. */ + OI_SDP_INVALID_CONNECTION_ID = 838, /**< SDP: Invalid connection ID in an SDP request */ + OI_SDP_CANNOT_SET_ATTRIBUTE = 839, /**< SDP: Attempt to set a dynamic attribute value failed */ + OI_SDP_BADLY_FORMED_ATTRIBUTE_VALUE = 840, /**< SDP: An attribute value has the wrong type or structure */ + OI_SDP_NO_ATTRIBUTE_LIST_TO_REMOVE = 841, /**< SDP: Attempt to remove a non-existent attribute list from a service record */ + OI_SDP_ATTRIBUTE_LIST_ALREADY_ADDED = 842, /**< SDP: An attribute list has already been added to the service record */ + OI_SDP_DATA_ELEMENT_TRUNCATED = 843, /**< SDP: Data element truncated (too few bytes) */ + + OI_RFCOMM_WRITE_IN_PROGRESS = 901, /**< RFCOMM: Write in progress */ + OI_RFCOMM_INVALID_BAUDRATE = 903, /**< RFCOMM: Invalid baudrate */ + OI_RFCOMM_INVALID_DATABIT = 904, /**< RFCOMM: Invalid databit */ + OI_RFCOMM_INVALID_STOPBIT = 905, /**< RFCOMM: Invalid stopbit */ + OI_RFCOMM_INVALID_PARITY = 906, /**< RFCOMM: Invalid parity */ + OI_RFCOMM_INVALID_PARITYTYPE = 907, /**< RFCOMM: Invalid paritytype */ + OI_RFCOMM_INVALID_FLOWCONTROL = 908, /**< RFCOMM: Invalid flowcontrol */ + OI_RFCOMM_SESSION_EXISTS = 909, /**< RFCOMM: Session exists */ + OI_RFCOMM_INVALID_CHANNEL = 910, /**< RFCOMM: Invalid channel */ + OI_RFCOMM_DLCI_EXISTS = 911, /**< RFCOMM: DLCI exists */ + OI_RFCOMM_LINK_NOT_FOUND = 912, /**< RFCOMM: Link not found */ + OI_RFCOMM_REMOTE_REJECT = 913, /**< RFCOMM: Remote reject */ + OI_RFCOMM_TEST_IN_PROGRESS = 915, /**< RFCOMM: Test in progress */ + OI_RFCOMM_SESSION_NOT_FOUND = 916, /**< RFCOMM: Session not found */ + OI_RFCOMM_INVALID_PACKET = 917, /**< RFCOMM: Invalid packet */ + OI_RFCOMM_FRAMESIZE_EXCEEDED = 918, /**< RFCOMM: Framesize exceeded */ + OI_RFCOMM_INVALID_DLCI = 920, /**< RFCOMM: Invalid dlci */ + OI_RFCOMM_SERVER_NOT_REGISTERED = 921, /**< RFCOMM: Server not registered */ + OI_RFCOMM_CREDIT_ERROR = 922, /**< RFCOMM: Credit error */ + OI_RFCOMM_NO_CHANNEL_NUMBER = 923, /**< RFCOMM: No channel number */ + OI_RFCOMM_QUERY_IN_PROGRESS = 924, /**< RFCOMM: Query in progress */ + OI_RFCOMM_SESSION_SHUTDOWN = 925, /**< RFCOMM: Session shutdown */ + OI_RFCOMM_LOCAL_DEVICE_DISCONNECTED = 926, /**< RFCOMM: Local device disconnected */ + OI_RFCOMM_REMOTE_DEVICE_DISCONNECTED = 927, /**< RFCOMM: Remote device disconnected */ + OI_RFCOMM_OUT_OF_SERVER_CHANNELS = 928, /**< RFCOMM: Out of server channels */ + + OI_DISPATCH_INVALID_CB_HANDLE = 1001, /**< Dispatcher was handed an invalid callback handle */ + OI_DISPATCH_TABLE_OVERFLOW = 1002, /**< Dispatcher table is full */ + + OI_TEST_UNKNOWN_TEST = 1101, /**< TEST: Unknown test */ + OI_TEST_FAIL = 1102, /**< TEST: Fail */ + + OI_HCITRANS_CANNOT_CONNECT_TO_DEVICE = 1201, /**< TRANSPORT: Cannot connect to device */ + OI_HCITRANS_BUFFER_TOO_SMALL = 1203, /**< TRANSPORT: Buffer too small */ + OI_HCITRANS_NULL_DEVICE_HANDLE = 1204, /**< TRANSPORT: Null device handle */ + OI_HCITRANS_IO_ERROR = 1205, /**< TRANSPORT: IO error */ + OI_HCITRANS_DEVICE_NOT_READY = 1206, /**< TRANSPORT: Device not ready */ + OI_HCITRANS_FUNCTION_NOT_SUPPORTED = 1207, /**< TRANSPORT: Function not supporteD */ + OI_HCITRANS_ACCESS_DENIED = 1209, /**< TRANSPORT: win32 */ + OI_HCITRANS_ACL_DATA_ERROR = 1210, /**< TRANSPORT: ACL data error */ + OI_HCITRANS_SCO_DATA_ERROR = 1211, /**< TRANSPORT: SCO data error */ + OI_HCITRANS_EVENT_DATA_ERROR = 1212, /**< TRANSPORT: HCI event data error */ + OI_HCITRANS_INTERNAL_ERROR = 1214, /**< TRANSPORT: Internal error in the transport */ + OI_HCITRANS_LINK_NOT_ACTIVE = 1215, /**< TRANSPORT: Link to the device is not currently active */ + OI_HCITRANS_INITIALIZING = 1216, /**< TRANSPORT: Transport is initializing */ + + OI_DEVMGR_NO_CONNECTION = 1301, /**< DEVMGR: No connection */ + OI_DEVMGR_HARDWARE_ERROR = 1305, /**< DEVMGR: error reported by HCI */ + OI_DEVMGR_PENDING_CONNECT_LIST_FULL = 1307, /**< DEVMGR: Pending connect list full */ + OI_DEVMGR_CONNECTION_LIST_FULL = 1309, /**< DEVMGR: Connection list full */ + OI_DEVMGR_NO_SUCH_CONNECTION = 1310, /**< DEVMGR: No such connection */ + OI_DEVMGR_INQUIRY_IN_PROGRESS = 1311, /**< DEVMGR: Inquiry in progress */ + OI_DEVMGR_PERIODIC_INQUIRY_ACTIVE = 1312, /**< DEVMGR: Periodic inquiry active */ + OI_DEVMGR_NO_INQUIRIES_ACTIVE = 1313, /**< DEVMGR: can not cancel/exit if not active */ + OI_DEVMGR_DUPLICATE_CONNECTION = 1314, /**< DEVMGR: internal error */ + OI_DEVMGR_DUPLICATE_EVENT_CALLBACK = 1316, /**< DEVMGR: attempt to register same callback twice */ + OI_DEVMGR_EVENT_CALLBACK_LIST_FULL = 1317, /**< DEVMGR: can not register event callback, list is full */ + OI_DEVMGR_EVENT_CALLBACK_NOT_FOUND = 1318, /**< DEVMGR: attempt to unregister callback failed */ + OI_DEVMGR_BUSY = 1319, /**< DEVMGR: some operations can only execute one at a time */ + OI_DEVMGR_ENUM_UNEXPECTED_INQ_COMPLETE = 1320, /**< DEVMGR: inquiry complete event in inappropriate enumeration state */ + OI_DEVMGR_ENUM_UNEXPECTED_INQ_RESULT = 1321, /**< DEVMGR: inquiry result event in inappropriate enumeration state */ + OI_DEVMGR_ENUM_DATABASE_FULL = 1322, /**< DEVMGR: device enumeration, database is full, couldn't add a new device */ + OI_DEVMGR_ENUM_INQUIRIES_OVERLAP = 1323, /**< DEVMGR: device enumeration, periodic inquiries occurring too close together */ + OI_DEVMGR_UNKNOWN_LINK_TYPE = 1324, /**< DEVMGR: HCI connect request with unkown link type */ + OI_DEVMGR_PARAM_IO_ACTIVE = 1325, /**< DEVMGR: request for parameter read/write while param read/write active */ + OI_DEVMGR_UNKNOWN_IAC_LAP = 1326, /**< DEVMGR: unrecognized IAC LAP */ + OI_DEVMGR_SCO_ALREADY_REGISTERED = 1327, /**< DEVMGR: only one application can use SCO */ + OI_DEVMGR_SCO_NOT_REGISTERED = 1328, /**< DEVMGR: SCO applications must register before using the API */ + OI_DEVMGR_SCO_WITHOUT_ACL = 1329, /**< DEVMGR: Got SCO connection but there is no underlying ACL connection */ + OI_DEVMGR_NO_SUPPORT = 1330, /**< DEVMGR: Request is not supported by the device */ + OI_DEVMGR_WRITE_POLICY_FAILED = 1331, /**< DEVMGR: connection attempt failed - unable to write link policy */ + OI_DEVMGR_NOT_IN_MASTER_MODE = 1332, /**< DEVMGR: OI_DEVMGR EndMasterMode without prior OI_DEVMGR_BeginMasterMode */ + OI_DEVMGR_POLICY_VIOLATION = 1333, /**< DEVMGR: low-power request is rejected - link policy does not allow it */ + OI_DEVMGR_BUSY_TIMEOUT = 1334, /**< DEVMGR: queued operation timed out while in the queue; \n + timeout configurable via @ref OI_CONFIG_DEVMGR::connectQueueTimeoutSecs "connectQueueTimeoutSecs" */ + OI_DEVMGR_REENCRYPT_FAILED = 1335, /**< DEVMGR: failed to re-encrypt link after role switch */ + OI_DEVMGR_ROLE_POLICY_CONFLICT = 1336, /**< DEVMGR: requested role conflicts with current policy */ + OI_DEVMGR_BAD_INTERVAL = 1337, /**< DEVMGR: current linkTO outside range of requested min/max interval */ + OI_DEVMGR_INVALID_SCO_HANDLE = 1338, /**< DEVMGR: HCI SCO event, invalid handle */ + OI_DEVMGR_CONNECTION_OVERLAP = 1339, /**< DEVMGR: Connection failed due to race condition with remote side */ + OI_DEVMGR_ORPHAN_SUBRATE_COMPLETE = 1340, /**< DEVMGR: sniff subrate complete, but no callback */ + OI_DEVMGR_EIR_RESPONSE_2_LARGE = 1341, /**< DEVMGR: eir builder, response length would exceed spec max */ + + OI_SECMGR_NO_POLICY = 1401, /**< SECMGR: no security policy has been established */ + OI_SECMGR_INTERNAL_ERROR = 1402, /**< SECMGR: internal inconsistency */ + OI_SECMGR_ORPHANED_CALLBACK = 1403, /**< SECMGR: we've been called back, but CB context is gone */ + OI_SECMGR_BUSY = 1404, /**< SECMGR: configure and access request cannot be concurrent */ + OI_SECMGR_DEVICE_NOT_TRUSTED = 1405, /**< SECMGR: l2cap access denied - device is not trusted */ + OI_SECMGR_DEVICE_ENCRYPT_FAIL = 1407, /**< SECMGR: l2cap access denied - failed to start encryption */ + OI_SECMGR_DISCONNECTED_FAIL = 1408, /**< SECMGR: l2cap access denied - disconnected */ + OI_SECMGR_ACCESS_PENDING = 1409, /**< SECMGR: l2cap access request is still pending */ + OI_SECMGR_PIN_CODE_TOO_SHORT = 1410, /**< SECMGR: Higher-layer process gave us a pin code that is too short */ + OI_SECMGR_UNKNOWN_ENCRYPT_VALUE = 1411, /**< SECMGR: got EncryptionChange event, unknown encryption enable value */ + OI_SECMGR_INVALID_POLICY = 1412, /**< SECMGR: the specified security policy is not valid for security mode */ + OI_SECMGR_AUTHORIZATION_FAILED = 1413, /**< SECMGR: device authorization failed */ + OI_SECMGR_ENCRYPTION_FAILED = 1414, /**< SECMGR: device encryption failed */ + OI_SECMGR_UNIT_KEY_UNSUPPORTED = 1415, /**< SECMGR: authentication failed due to non-support of unit keys */ + OI_SECMGR_NOT_REGISTERED = 1416, /**< SECMGR: required registrations have not yet occurred */ + OI_SECMGR_ILLEGAL_WRITE_SSP_MODE = 1417, /**< SECMGR: 2.1 HCI spec does not allow SSP mode to be disabled */ + OI_SECMGR_INVALID_SEC_LEVEL = 1418, /**< SECMGR: security level for a service is not a valid value */ + OI_SECMGR_INSUFFICIENT_LINK_KEY = 1419, /**< SECMGR: link key type is not sufficient to meet service requirements */ + OI_SECMGR_INVALID_KEY_TYPE = 1420, /**< SECMGR: link key type is not a valid value */ + OI_SECMGR_SSP_NOT_ENCRYPTED = 1421, /**< SECMGR: ssp required encryption on incoming link */ + OI_SECMGR_ORPHAN_EVENT = 1422, /**< SECMGR: some HCI security event unrelated to current processes */ + OI_SECMGR_NOT_BONDABLE = 1423, /**< SECMGR: not in bondable mode */ + + OI_TCS_INVALID_ELEMENT_TYPE = 1602, /**< TCS: element type is invalid */ + OI_TCS_INVALID_PACKET = 1603, /**< TCS: packet is invalide */ + OI_TCS_CALL_IN_PROGRESS = 1604, /**< TCS: call is in progress */ + OI_TCS_NO_CALL_IN_PROGRESS = 1605, /**< TCS: no call in progress */ + + OI_OBEX_CONTINUE = 1701, /**< OBEX: Continue processing OBEX request */ + OI_OBEX_COMMAND_ERROR = 1702, /**< OBEX: An unrecognized OBEX command opcode */ + OI_OBEX_CONNECTION_TIMEOUT = 1703, /**< OBEX: Timeout waiting for a response to a request */ + OI_OBEX_CONNECT_FAILED = 1704, /**< OBEX: An OBEX connection request did not succeed */ + OI_OBEX_DISCONNECT_FAILED = 1705, /**< OBEX: A disconnect failed probably because the connection did not exist */ + OI_OBEX_ERROR = 1706, /**< OBEX: Unspecified OBEX error */ + OI_OBEX_INCOMPLETE_PACKET = 1707, /**< OBEX: Packet too short or corrupt */ + OI_OBEX_LENGTH_REQUIRED = 1708, /**< OBEX: Length header required in OBEX command */ + OI_OBEX_NOT_CONNECTED = 1709, /**< OBEX: No connection to OBEX server */ + OI_OBEX_NO_MORE_CONNECTIONS = 1710, /**< OBEX: Reached max connections limit */ + OI_OBEX_OPERATION_IN_PROGRESS = 1711, /**< OBEX: Another operation is still in progress on a connection */ + OI_OBEX_PUT_RESPONSE_ERROR = 1712, /**< OBEX: An error in the response to a PUT command */ + OI_OBEX_GET_RESPONSE_ERROR = 1713, /**< OBEX: An error in the response to a GET command */ + OI_OBEX_REQUIRED_HEADER_NOT_FOUND = 1714, /**< OBEX: packet was missing a required header */ + OI_OBEX_SERVICE_UNAVAILABLE = 1715, /**< OBEX: Unown OBEX target or required service */ + OI_OBEX_TOO_MANY_HEADER_BYTES = 1716, /**< OBEX: Headers will not fit in single OBEX packet */ + OI_OBEX_UNKNOWN_COMMAND = 1717, /**< OBEX: Unrecognized OBEX command */ + OI_OBEX_UNSUPPORTED_VERSION = 1718, /**< OBEX: Version mismatch */ + OI_OBEX_CLIENT_ABORTED_COMMAND = 1719, /**< OBEX: server received abort command */ + OI_OBEX_BAD_PACKET = 1720, /**< OBEX: Any malformed OBEX packet */ + OI_OBEX_BAD_REQUEST = 1721, /**< OBEX: Maps to OBEX response of the same name */ + OI_OBEX_OBJECT_OVERFLOW = 1723, /**< OBEX: Too many bytes received. */ + OI_OBEX_NOT_FOUND = 1724, /**< OBEX: Maps to obex response of same name */ + OI_OBEX_ACCESS_DENIED = 1735, /**< OBEX: Object could not be read or written. */ + OI_OBEX_VALUE_NOT_ACCEPTABLE = 1736, /**< OBEX: Value in a command was not in the acceptable range. */ + OI_OBEX_PACKET_OVERFLOW = 1737, /**< OBEX: Buffer will not fit in a single OBEX packet. */ + OI_OBEX_NO_SUCH_FOLDER = 1738, /**< OBEX: Error returned by a setpath operation. */ + OI_OBEX_NAME_REQUIRED = 1739, /**< OBEX: Name must be non-null and non-empty. */ + OI_OBEX_PASSWORD_TOO_LONG = 1740, /**< OBEX: Password exceeds implementation imposed length limit. */ + OI_OBEX_PRECONDITION_FAILED = 1741, /**< OBEX: response Precondition Failed */ + OI_OBEX_UNAUTHORIZED = 1742, /**< OBEX: authentication was not successful. */ + OI_OBEX_NOT_IMPLEMENTED = 1743, /**< OBEX: Unimplemented feature. */ + OI_OBEX_INVALID_AUTH_DIGEST = 1744, /**< OBEX: An authentication digest was bad. */ + OI_OBEX_INVALID_OPERATION = 1745, /**< OBEX: Operation not allowed at this time. */ + OI_OBEX_DATABASE_FULL = 1746, /**< OBEX: Sync database full. */ + OI_OBEX_DATABASE_LOCKED = 1747, /**< OBEX: Sync database locked. */ + OI_OBEX_INTERNAL_SERVER_ERROR = 1748, /**< OBEX: response Internal Server Error */ + OI_OBEX_UNSUPPORTED_MEDIA_TYPE = 1749, /**< OBEX: response Unsupported Media Type */ + OI_OBEX_PARTIAL_CONTENT = 1750, /**< OBEX: response Partial Content */ + OI_OBEX_METHOD_NOT_ALLOWED = 1751, /**< OBEX: response Method Not Allowed */ + OI_OBEXSRV_INCOMPLETE_GET = 1752, /**< OBEX: Indicates to a GET handler that the request phase is still in progress */ + OI_OBEX_FOLDER_BROWSING_NOT_ALLOWED = 1753, /**< OBEX: Indicates that an FTP server does not allow folder browsing */ + OI_OBEX_SERVER_FORCED_DISCONNECT = 1754, /**< OBEX: connection was forcibly terminated by the server */ + OI_OBEX_OFS_ERROR = 1755, /**< OBEX: OPP object file system error occurred */ + OI_OBEX_FILEOP_ERROR = 1756, /**< OBEX: FTP/PBAP file operation system error occurred */ + OI_OBEX_USERID_TOO_LONG = 1757, /**< OBEX: User Id exceeds spec limited length limit. */ + + OI_HANDSFREE_EVENT_REPORTING_DISABLED = 1801, /**< HANDSFREE: Event reporting disabled */ + OI_HANDSFREE_NOT_CONNECTED = 1802, /**< HANDSFREE: Not connected */ + OI_HANDSFREE_SERVICE_NOT_STARTED = 1803, /**< HANDSFREE: Cannot connect to handsfree AG if handsfree service not started */ + OI_HANDSFREE_AG_SERVICE_NOT_STARTED = 1804, /**< HANDSFREE: Cannot connect to handsfree device if handsfree AG service not started */ + OI_HANDSFREE_COMMAND_IN_PROGRESS = 1805, /**< HANDSFREE: Cannot accept a command at this time */ + OI_HANDSFREE_AUDIO_ALREADY_CONNECTED = 1806, /**< HANDSFREE: Audio is already connected */ + OI_HANDSFREE_AUDIO_NOT_CONNECTED = 1807, /**< HANDSFREE: Audio is not connected */ + OI_HANDSFREE_FEATURE_NOT_SUPPORTED = 1808, /**< HANDSFREE: Local or remote feature not supported for requested command */ + + OI_HEADSET_SERVICE_NOT_STARTED = 1901, /**< HEADSET: Cannot connect to headset AG if headset service not started */ + OI_HEADSET_AG_SERVICE_NOT_STARTED = 1902, /**< HEADSET: Cannot connect to headset device if headset AG service not started */ + OI_HEADSET_COMMAND_IN_PROGRESS = 1903, /**< HEADSET: Cannot accept a command at this time */ + + OI_BNEP_INVALID_MTU = 2001, /**< BNEP: The remote device cannot support the minimum BNEP MTU */ + OI_BNEP_SETUP_TIMEOUT = 2002, /**< BNEP: The setup request timed out. */ + OI_BNEP_SERVICE_NOT_REGISTERED = 2003, /**< BNEP: The requested service was not found. */ + OI_BNEP_INVALID_HANDLE = 2004, /**< BNEP: The specified connection handle is not valid. */ + OI_BNEP_RESPONSE_TIMEOUT = 2005, /**< BNEP: The timer for receiving a response has expired. */ + OI_BNEP_INVALID_CONNECTION = 2006, /**< BNEP: Invalid connection */ + OI_BNEP_INVALID_FILTER = 2007, /**< BNEP: The supplied filter was invalid. */ + OI_BNEP_CONNECTION_EXISTS = 2008, /**< BNEP: An attempt was made to create a duplicate connection. */ + OI_BNEP_NOT_INITIALIZED = 2009, /**< BNEP: Init has not been called */ + OI_BNEP_CONNECT_BASE = 2010, /**< BNEP: connection response codes */ + OI_BNEP_CONNECT_FAILED_INVALID_DEST_UUID = 2011, /**< BNEP: connect response code Invalid Dest UUID */ + OI_BNEP_CONNECT_FAILED_INVALID_SOURCE_UUID = 2012, /**< BNEP: connect response code Invalid Source UUID */ + OI_BNEP_CONNECT_FAILED_INVALID_UUID_SIZE = 2013, /**< BNEP: connect response code Invalid UUID Size */ + OI_BNEP_CONNECT_FAILED_NOT_ALLOWED = 2014, /**< BNEP: connect response code Not Allowed */ + OI_BNEP_FILTER_NET_BASE = 2020, /**< BNEP: filter response codes */ + OI_BNEP_FILTER_NET_UNSUPPORTED_REQUEST = 2021, /**< BNEP: filter response code Unsupported Request */ + OI_BNEP_FILTER_NET_FAILED_INVALID_PROTOCOL_TYPE = 2022, /**< BNEP: filter response code Invalid Protocol Type */ + OI_BNEP_FILTER_NET_FAILED_MAX_LIMIT_REACHED = 2023, /**< BNEP: filter response code Max Limit Reached */ + OI_BNEP_FILTER_NET_FAILED_SECURITY = 2024, /**< BNEP: filter response code Security */ + OI_BNEP_FILTER_MULTI_BASE = 2030, /**< BNEP: multicast response codes */ + OI_BNEP_FILTER_MULTI_UNSUPPORTED_REQUEST = 2031, /**< BNEP: multicast response code Unsupported Request */ + OI_BNEP_FILTER_MULTI_FAILED_INVALID_ADDRESS = 2032, /**< BNEP: multicast response code Invalid Address */ + OI_BNEP_FILTER_MULTI_FAILED_MAX_LIMIT_REACHED = 2033, /**< BNEP: multicast response code Max Limit Reached */ + OI_BNEP_FILTER_MULTI_FAILED_SECURITY = 2034, /**< BNEP: multicast response code Security */ + OI_BNEP_LOCAL_DEVICE_MUST_BE_MASTER = 2040, /**< BNEP: Device must be master of the piconet for this function */ + OI_BNEP_PACKET_FILTERED_OUT = 2041, /**< BNEP: Packet did not pass current filters */ + + OI_NETIFC_UP_FAILED = 2101, /**< NETIFC: Could not bring up network interface */ + OI_NETIFC_COULD_NOT_CREATE_THREAD = 2102, /**< NETIFC: Network interface could not create a read thread */ + OI_NETIFC_INITIALIZATION_FAILED = 2103, /**< NETIFC: Error in network interface initialization */ + OI_NETIFC_INTERFACE_ALREADY_UP = 2104, /**< NETIFC: Network interface is already up */ + OI_NETIFC_INTERFACE_NOT_UP = 2105, /**< NETIFC: Network interface is not up */ + OI_NETIFC_PACKET_TOO_BIG = 2106, /**< NETIFC: The packet is too big */ + + OI_PAN_ROLE_ALREADY_REGISTERED = 2201, /**< PAN: This PAN role was already registered */ + OI_PAN_ROLE_NOT_ALLOWED = 2202, /**< PAN: The PAN role is not currently allowed */ + OI_PAN_INCOMPATIBLE_ROLES = 2203, /**< PAN: Only certain local and remote role combinations are permitted */ + OI_PAN_INVALID_ROLE = 2204, /**< PAN: Role specified is not one the defined PAN roles */ + OI_PAN_CONNECTION_IN_PROGRESS = 2205, /**< PAN: A PAN connection is currently being established */ + OI_PAN_USER_ALREADY_CONNECTED = 2206, /**< PAN: PAN user role only allows a single connection */ + OI_PAN_DEVICE_CONNECTED = 2207, /**< PAN: A PAN connection already exists to specified device */ + + OI_CODEC_SBC_NO_SYNCWORD = 2301, /**< CODEC: Couldn't find an SBC SYNCWORD */ + OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA = 2302, /**< CODEC: Not enough data provided to decode an SBC header */ + OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA = 2303, /**< CODEC: Decoded the header, but not enough data to contain the rest of the frame */ + OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA = 2304, /**< CODEC: Not enough audio data for this frame */ + OI_CODEC_SBC_CHECKSUM_MISMATCH = 2305, /**< CODEC: The frame header didn't match the checksum */ + OI_CODEC_SBC_PARTIAL_DECODE = 2306, /**< CODEC: Decoding was successful, but frame data still remains. Next call will provide audio without consuming input data. */ + + OI_FIFOQ_QUEUE_NOT_ALIGNED = 2401, /**< FIFOQ: queue must be 32-bit aligned */ + OI_FIFOQ_INVALID_Q = 2402, /**< FIFOQ: queue parameter is not a valid queue */ + OI_FIFOQ_BUF_TOO_LARGE = 2403, /**< FIFOQ: attempt to queue a buffer which is too large */ + OI_FIFOQ_FULL = 2404, /**< FIFOQ: enqueue() failed, queue is full */ + OI_FIFOQ_NOT_ALLOCATED = 2405, /**< FIFOQ: Enqueue QBuf() failed, buffer not allocated */ + OI_FIFOQ_INVALID_DATA_PTR = 2406, /**< FIFOQ: Enqueue QBuf() failed, data pointer does not match */ + + OI_HID_HOST_SERVICE_NOT_STARTED = 2601, /**< HID: Cannot connect to a HID device unless HID host is started */ + OI_HID_DEVICE_SERVICE_NOT_STARTED = 2602, /**< HID: Cannot connect to a HID host unless HID device is started */ + + OI_AT_ERROR = 2701, /**< AT: ERROR response */ + OI_AT_NO_CARRIER = 2702, /**< AT: NO CARRIER response */ + OI_AT_BUSY = 2703, /**< AT: BUSY response */ + OI_AT_NO_ANSWER = 2704, /**< AT: NO ANSWER response */ + OI_AT_DELAYED = 2705, /**< AT: DELAYED response */ + OI_AT_BLACKLISTED = 2706, /**< AT: BLACKLISTED response */ + OI_AT_CME_ERROR = 2707, /**< AT: +CME ERROR response */ + OI_AT_CMS_ERROR = 2708, /**< AT: +CMS ERROR response */ + + OI_BLST_CHARACTER_TIMEOUT = 2801, /**< BLST: Timeout expired while waiting for a character from the client. */ + OI_BLST_ACKNOWLDGE_TIMEOUT = 2802, /**< BLST: Timeout expired while waiting for event acknowledgment from the client */ + OI_BLST_TX_NOT_READY = 2803, /**< BLST: BLST is not ready to send a BHAPI message to the client. */ + OI_BLST_TX_BUSY = 2804, /**< BLST: BLST transmit buffer is in use. */ + + OI_AVDTP_CONNECTION_SEQ_ERROR = 2901, /**< AVDTP: sequencing of signalling/media channel connections broken. */ + OI_AVDTP_OUT_OF_RESOURCES = 2902, /**< AVDTP: Tried to allocate too many endpoints or signalling channels. */ + + OI_PBAP_REPOSITORY_NOT_SET = 3001, /**< PBAP: Phonebook repository must be set for operation to complete. */ + OI_PBAP_PHONEBOOK_NOT_SET = 3002, /**< PBAP: Phonebook be set for operation to complete. */ + + OI_AADP_BAD_ENDPOINT = 3101, /**< AADP: Invalid local endpoint specified */ + OI_AADP_BAD_STATE = 3102, /**< AADP: AADP State is not correct for this operation. */ + + OI_UNICODE_INVALID_SOURCE = 3200, /**< Unicode Conversion: Source string has invalid character encoding. */ + OI_UNICODE_SOURCE_EXHAUSTED = 3201, /**< Unicode Conversion: Incomplete Unicode character at end of source buffer. */ + OI_UNICODE_DESTINATION_EXHAUSTED = 3202, /**< Unicode Conversion: Destination buffer not large enough to hold resulting Unicode string. */ + + OI_AVRCP_TOO_MANY_CONNECTIONS = 3300, /**< AVRCP: Exceeded maximum number of simultaneous AVCTP connections. */ + OI_AVRCP_NOT_IMPLEMENTED = 3301, /**< AVRCP: The target does not implement the command specified by the opcode and operand. */ + OI_AVRCP_REJECTED = 3302, /**< AVRCP: The target cannot respond because of invalid operands in command packet. */ + OI_AVRCP_INVALID_RESPONSE = 3303, /**< AVRCP: The controller received the response with invalid parameters */ + OI_AVRCP_RESPONSE_PACKET_OVERFLOW = 3304, /**< AVRCP: The response message does not fir in one AVRCP packet (512 bytes), has to be fragmented. */ + OI_AVRCP_RESPONSE_INVALID_PDU = 3305, /**< AVRCP: Command rejected: target received a PDU that it did not understand. */ + OI_AVRCP_RESPONSE_INVALID_PARAMETER = 3306, /**< AVRCP: Command rejected: target received a PDU with a parameter ID that it did not understand. */ + OI_AVRCP_RESPONSE_PARAMETER_NOT_FOUND = 3307, /**< AVRCP: Command rejected: specified parameter not found, sent if the parameter ID is understood, but content is wrong or corrupted.*/ + OI_AVRCP_RESPONSE_INTERNAL_ERROR = 3308, /**< AVRCP: Command rejected: target detected other error conditions. */ + OI_MAX_BM3_STATUS_VAL, /* Maximum BM3 status code */ + + /* Status code values reserved for BM3 SDK platform-specific implementations */ + OI_STATUS_RESERVED_FOR_BCOT = 9000, + + /* Status code values reserved for BHAPI products */ + OI_STATUS_RESERVED_FOR_BHAPI = 9200, + + /* Status code values reserved for Soundabout products */ + OI_STATUS_RESERVED_FOR_SOUNDABOUT = 9400, + + /* + * Status code values greater than or equal to this value are reserved for use by applications. + * However, because of differences between compilers, and differences between 16-bit and 32-bit + * platforms custom status codes should be in the 16-bit range, so status codes can range from 0 + * to 65534, inclusive (65535 is reserved) + */ + OI_STATUS_RESERVED_FOR_APPS = 10000, + + + + OI_STATUS_NONE = 0xffff /**< Special status code to indicate that there is no status. (Only to be used for special cases involving OI_SLOG_ERROR() and OI_SLOG_WARNING().) */ + +} OI_STATUS; + + +/* Remeber to update the #define below when new reserved blocks are added to + * the list above. */ +#define OI_NUM_RESERVED_STATUS_BLOCKS 4 /**< Number of status code blocks reserved, including user apps */ + + +/** + * Test for success + */ +#define OI_SUCCESS(x) ((x) == OI_OK) + +/*****************************************************************************/ +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* _OI_STATUS_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_stddefs.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_stddefs.h new file mode 100644 index 0000000000..9ab424db2e --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_stddefs.h @@ -0,0 +1,232 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 OI_STDDEFS_H +#define OI_STDDEFS_H +/** + * @file + * This file contains BM3 standard type definitions. + * + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#include "oi_cpu_dep.h" + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef FALSE +#define FALSE 0 /**< This define statement sets FALSE as a preprocessor alias for 0. */ +#endif + +#ifndef TRUE +#define TRUE (!FALSE) /**< This define statement sets TRUE as a preprocessor alias for !FALSE. */ +#endif + +#ifdef HEW_TOOLCHAIN +#ifdef NULL +#undef NULL /**< Override HEW toolchain NULL definition */ +#endif +#define NULL 0 /**< HEW toolchain does not allow us to compare (void*) type to function pointer */ +#else +#ifndef NULL +#define NULL ((void*)0) /**< This define statement sets NULL as a preprocessor alias for (void*)0 */ +#endif +#endif + +/** + * @name Maximum and minimum values for basic types + * @{ + */ +#define OI_INT8_MIN ((OI_INT8)0x80) /**< decimal value: -128 */ +#define OI_INT8_MAX ((OI_INT8)0x7F) /**< decimal value: 127 */ +#define OI_INT16_MIN ((OI_INT16)0x8000) /**< decimal value: -32768 */ +#define OI_INT16_MAX ((OI_INT16)0x7FFF) /**< decimal value: 32767 */ +#define OI_INT32_MIN ((OI_INT32)0x80000000) /**< decimal value: -2,147,483,648 */ +#define OI_INT32_MAX ((OI_INT32)0x7FFFFFFF) /**< decimal value: 2,147,483,647 */ +#define OI_UINT8_MIN ((OI_UINT8)0) /**< decimal value: 0 */ +#define OI_UINT8_MAX ((OI_UINT8)0xFF) /**< decimal value: 255 */ +#define OI_UINT16_MIN ((OI_UINT16)0) /**< decimal value: 0 */ +#define OI_UINT16_MAX ((OI_UINT16)0xFFFF) /**< decimal value: 65535 */ +#define OI_UINT32_MIN ((OI_UINT32)0) /**< decimal value: 0 */ +#define OI_UINT32_MAX ((OI_UINT32)0xFFFFFFFF) /**< decimal value: 4,294,967,295 */ + +/** + * @} + */ + +/** + * @name Integer types required by the Service Discovery Protocol + * @{ + */ + +/** unsigned 64-bit integer as a structure of two unsigned 32-bit integers */ +typedef struct { + OI_UINT32 I1; /**< most significant 32 bits */ + OI_UINT32 I2; /**< least significant 32 bits */ +} OI_UINT64; + +#define OI_UINT64_MIN { (OI_UINT32)0x00000000, (OI_UINT32)0x00000000 } +#define OI_UINT64_MAX { (OI_UINT32)0XFFFFFFFF, (OI_UINT32)0XFFFFFFFF } + +/** signed 64-bit integer as a structure of one unsigned 32-bit integer and one signed 32-bit integer */ +typedef struct { + OI_INT32 I1; /**< most significant 32 bits as a signed integer */ + OI_UINT32 I2; /**< least significant 32 bits as an unsigned integer */ +} OI_INT64; + +#define OI_INT64_MIN { (OI_INT32)0x80000000, (OI_UINT32)0x00000000 } +#define OI_INT64_MAX { (OI_INT32)0X7FFFFFFF, (OI_UINT32)0XFFFFFFFF } + +/** unsigned 128-bit integer as a structure of four unsigned 32-bit integers */ +typedef struct { + OI_UINT32 I1; /**< most significant 32 bits */ + OI_UINT32 I2; /**< second-most significant 32 bits */ + OI_UINT32 I3; /**< third-most significant 32 bits */ + OI_UINT32 I4; /**< least significant 32 bits */ +} OI_UINT128; + +#define OI_UINT128_MIN { (OI_UINT32)0x00000000, (OI_UINT32)0x00000000, (OI_UINT32)0x00000000, (OI_UINT32)0x00000000 } +#define OI_UINT128_MAX { (OI_UINT32)0XFFFFFFFF, (OI_UINT32)0XFFFFFFFF, (OI_UINT32)0XFFFFFFFF, (OI_UINT32)0XFFFFFFFF } + +/** signed 128-bit integer as a structure of three unsigned 32-bit integers and one signed 32-bit integer */ +typedef struct { + OI_INT32 I1; /**< most significant 32 bits as a signed integer */ + OI_UINT32 I2; /**< second-most significant 32 bits as an unsigned integer */ + OI_UINT32 I3; /**< third-most significant 32 bits as an unsigned integer */ + OI_UINT32 I4; /**< least significant 32 bits as an unsigned integer */ +} OI_INT128; + +#define OI_INT128_MIN { (OI_UINT32)0x80000000, (OI_UINT32)0x00000000, (OI_UINT32)0x00000000, (OI_UINT32)0x00000000 } +#define OI_INT128_MAX { (OI_UINT32)0X7FFFFFFF, (OI_UINT32)0XFFFFFFFF, (OI_UINT32)0XFFFFFFFF, (OI_UINT32)0XFFFFFFFF } + +/** + * @} + */ + + +/** + * type for ASCII character data items + */ +typedef char OI_CHAR; + +/** + * type for double-byte character data items + */ +typedef OI_UINT16 OI_CHAR16; + +/** + * types for UTF encoded strings. + */ +typedef OI_UINT8 OI_UTF8; +typedef OI_UINT16 OI_UTF16; +typedef OI_UINT32 OI_UTF32; + + +/** + * @name Single-bit operation macros + * @{ + * In these macros, x is the data item for which a bit is to be tested or set and y specifies which bit + * is to be tested or set. + */ + +/** This macro's value is TRUE if the bit specified by y is set in data item x. */ +#define OI_BIT_TEST(x,y) ((x) & (y)) + +/** This macro's value is TRUE if the bit specified by y is not set in data item x. */ +#define OI_BIT_CLEAR_TEST(x,y) (((x) & (y)) == 0) + +/** This macro sets the bit specified by y in data item x. */ +#define OI_BIT_SET(x,y) ((x) |= (y)) + +/** This macro clears the bit specified by y in data item x. */ +#define OI_BIT_CLEAR(x,y) ((x) &= ~(y)) + +/** @} */ + +/** + * The OI_ARRAYSIZE macro is set to the number of elements in an array + * (instead of the number of bytes, which is returned by sizeof()). + */ + +#ifndef OI_ARRAYSIZE +#define OI_ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) +#endif + +/** + * @name Preprocessor aliases for individual bit positions + * Bits are defined here only if they are not already defined. + * @{ + */ + +#ifndef BIT0 + +#define BIT0 0x00000001 /**< preprocessor alias for 32-bit value with bit 0 set, used to specify this single bit */ +#define BIT1 0x00000002 /**< preprocessor alias for 32-bit value with bit 1 set, used to specify this single bit */ +#define BIT2 0x00000004 /**< preprocessor alias for 32-bit value with bit 2 set, used to specify this single bit */ +#define BIT3 0x00000008 /**< preprocessor alias for 32-bit value with bit 3 set, used to specify this single bit */ +#define BIT4 0x00000010 /**< preprocessor alias for 32-bit value with bit 4 set, used to specify this single bit */ +#define BIT5 0x00000020 /**< preprocessor alias for 32-bit value with bit 5 set, used to specify this single bit */ +#define BIT6 0x00000040 /**< preprocessor alias for 32-bit value with bit 6 set, used to specify this single bit */ +#define BIT7 0x00000080 /**< preprocessor alias for 32-bit value with bit 7 set, used to specify this single bit */ +#define BIT8 0x00000100 /**< preprocessor alias for 32-bit value with bit 8 set, used to specify this single bit */ +#define BIT9 0x00000200 /**< preprocessor alias for 32-bit value with bit 9 set, used to specify this single bit */ +#define BIT10 0x00000400 /**< preprocessor alias for 32-bit value with bit 10 set, used to specify this single bit */ +#define BIT11 0x00000800 /**< preprocessor alias for 32-bit value with bit 11 set, used to specify this single bit */ +#define BIT12 0x00001000 /**< preprocessor alias for 32-bit value with bit 12 set, used to specify this single bit */ +#define BIT13 0x00002000 /**< preprocessor alias for 32-bit value with bit 13 set, used to specify this single bit */ +#define BIT14 0x00004000 /**< preprocessor alias for 32-bit value with bit 14 set, used to specify this single bit */ +#define BIT15 0x00008000 /**< preprocessor alias for 32-bit value with bit 15 set, used to specify this single bit */ +#define BIT16 0x00010000 /**< preprocessor alias for 32-bit value with bit 16 set, used to specify this single bit */ +#define BIT17 0x00020000 /**< preprocessor alias for 32-bit value with bit 17 set, used to specify this single bit */ +#define BIT18 0x00040000 /**< preprocessor alias for 32-bit value with bit 18 set, used to specify this single bit */ +#define BIT19 0x00080000 /**< preprocessor alias for 32-bit value with bit 19 set, used to specify this single bit */ +#define BIT20 0x00100000 /**< preprocessor alias for 32-bit value with bit 20 set, used to specify this single bit */ +#define BIT21 0x00200000 /**< preprocessor alias for 32-bit value with bit 21 set, used to specify this single bit */ +#define BIT22 0x00400000 /**< preprocessor alias for 32-bit value with bit 22 set, used to specify this single bit */ +#define BIT23 0x00800000 /**< preprocessor alias for 32-bit value with bit 23 set, used to specify this single bit */ +#define BIT24 0x01000000 /**< preprocessor alias for 32-bit value with bit 24 set, used to specify this single bit */ +#define BIT25 0x02000000 /**< preprocessor alias for 32-bit value with bit 25 set, used to specify this single bit */ +#define BIT26 0x04000000 /**< preprocessor alias for 32-bit value with bit 26 set, used to specify this single bit */ +#define BIT27 0x08000000 /**< preprocessor alias for 32-bit value with bit 27 set, used to specify this single bit */ +#define BIT28 0x10000000 /**< preprocessor alias for 32-bit value with bit 28 set, used to specify this single bit */ +#define BIT29 0x20000000 /**< preprocessor alias for 32-bit value with bit 29 set, used to specify this single bit */ +#define BIT30 0x40000000 /**< preprocessor alias for 32-bit value with bit 30 set, used to specify this single bit */ +#define BIT31 0x80000000 /**< preprocessor alias for 32-bit value with bit 31 set, used to specify this single bit */ + +#endif /* BIT0 et al */ + + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +/*****************************************************************************/ +#endif /* OI_STDDEFS_H */ diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_string.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_string.h new file mode 100644 index 0000000000..928acb07df --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_string.h @@ -0,0 +1,208 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 OI_STRING_H +#define OI_STRING_H +/** + * @file + * This file contains BM3 supplied portable string.h functions + * + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#include "oi_cpu_dep.h" +#include "oi_stddefs.h" + +#if defined(USE_NATIVE_MEMCPY) || defined(USE_NATIVE_MALLOC) +#include +#endif + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * If we are using Native malloc(), we must also use + * native Ansi string.h functions for memory manipulation. + */ +#ifdef USE_NATIVE_MALLOC +#ifndef USE_NATIVE_MEMCPY +#define USE_NATIVE_MEMCPY +#endif +#endif + +#ifdef USE_NATIVE_MEMCPY + +#define OI_MemCopy(to, from, size) memcpy((to), (from), (size)) +#define OI_MemSet(block, val, size) memset((block), (val), (size)) +#define OI_MemZero(block, size) memset((block), 0, (size)) +#define OI_MemCmp(s1, s2, n) memcmp((s1), (s2), (n)) +#define OI_Strcpy(dest, src) strcpy((dest),(src)) +#define OI_Strcat(dest, src) strcat((dest),(src)) +#define OI_StrLen(str) strlen((str)) +#define OI_Strcmp(s1, s2) strcmp((s1), (s2)) +#define OI_Strncmp(s1, s2, n) strncmp((s1), (s2), (n)) + +#else + +/* + * OI_MemCopy + * + * Copy an arbitrary number of bytes from one memory address to another. + * The underlying implementation is the ANSI memmove() or equivalant, so + * overlapping memory copies will work correctly. + */ +void OI_MemCopy(void *To, void const *From, OI_UINT32 Size); + + +/* + * OI_MemSet + * + * Sets all bytes in a block of memory to the same value + */ +void OI_MemSet(void *Block, OI_UINT8 Val, OI_UINT32 Size); + + +/* + * OI_MemZero + * + * Sets all bytes in a block of memory to zero + */ +void OI_MemZero(void *Block, OI_UINT32 Size); + + +/* + * OI_MemCmp + * + * Compare two blocks of memory + * + * Returns: + * 0, if s1 == s2 + * < 0, if s1 < s2 + * > 0, if s2 > s2 + */ +OI_INT OI_MemCmp(void const *s1, void const *s2, OI_UINT32 n); + +/* + * OI_Strcpy + * + * Copies the Null terminated string from pStr to pDest, and + * returns pDest. + */ + +OI_CHAR *OI_Strcpy(OI_CHAR *pDest, + OI_CHAR const *pStr); + +/* + * OI_Strcat + * + * Concatonates the pStr string to the end of pDest, and + * returns pDest. + */ + +OI_CHAR *OI_Strcat(OI_CHAR *pDest, + OI_CHAR const *pStr) ; + +/* + * OI_StrLen + * + * Calculates the number of OI_CHARs in pStr (not including + * the Null terminator) and returns the value. + */ +OI_UINT OI_StrLen(OI_CHAR const *pStr) ; + +/* + * OI_Strcmp + * + * Compares two Null terminated strings + * + * Returns: + * 0, if s1 == s2 + * < 0, if s1 < s2 + * > 0, if s2 > s2 + */ +OI_INT OI_Strcmp(OI_CHAR const *s1, + OI_CHAR const *s2); + +/* + * OI_Strncmp + * + * Compares the first "len" OI_CHARs of strings s1 and s2. + * + * Returns: + * 0, if s1 == s2 + * < 0, if s1 < s2 + * > 0, if s2 > s2 + */ +OI_INT OI_Strncmp(OI_CHAR const *s1, + OI_CHAR const *s2, + OI_UINT32 len); + + +#endif /* USE_NATIVE_MEMCPY */ + +/* + * OI_StrcmpInsensitive + * + * Compares two Null terminated strings, treating + * the Upper and Lower case of 'A' through 'Z' as + * equivilent. + * + * Returns: + * 0, if s1 == s2 + * < 0, if s1 < s2 + * > 0, if s2 > s2 + */ +OI_INT OI_StrcmpInsensitive(OI_CHAR const *s1, + OI_CHAR const *s2); + +/* + * OI_StrncmpInsensitive + * + * Compares the first "len" OI_CHARs of strings s1 and s2, + * treating the Upper and Lower case of 'A' through 'Z' as + * equivilent. + * + * + * Returns: + * 0, if s1 == s2 + * < 0, if s1 < s2 + * > 0, if s2 > s2 + */ +OI_INT OI_StrncmpInsensitive(OI_CHAR const *s1, + OI_CHAR const *s2, + OI_UINT len); + + + +#ifdef __cplusplus +} +#endif + +/** @} */ + +/*****************************************************************************/ +#endif /* OI_STRING_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_time.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_time.h new file mode 100644 index 0000000000..40b8dfc4d7 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_time.h @@ -0,0 +1,200 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_TIME_H +#define _OI_TIME_H +/** @file + * + * This file provides time type definitions and interfaces to time-related functions. + * + * The stack maintains a 64-bit real-time millisecond clock. The choice of + * milliseconds is for convenience, not accuracy. + * + * Timeouts are specified as tenths of seconds in a 32-bit value. Timeout values + * specified by the Bluetooth specification are usually muliple seconds, so + * accuracy to a tenth of a second is more than adequate. + * + * This file also contains macros to convert between seconds and the Link + * Manager's 1.28-second units. + * + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#include "oi_stddefs.h" + + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * Within the core stack timeouts are specified in intervals of tenths of seconds + */ + +typedef OI_UINT16 OI_INTERVAL; +#define OI_INTERVALS_PER_SECOND 10 +#define MSECS_PER_OI_INTERVAL (1000 / OI_INTERVALS_PER_SECOND) + +/** maximum interval (54 min 36.7 sec) */ +#define OI_MAX_INTERVAL 0x7fff + + +/** + * Macro to convert seconds to OI_INTERVAL time units + */ + +#define OI_SECONDS(n) ((OI_INTERVAL) ((n) * OI_INTERVALS_PER_SECOND)) + +/** + * Macro to convert milliseconds to OI_INTERVAL time units (Rounded Up) + */ + +#define OI_MSECONDS(n) ((OI_INTERVAL) ((n + MSECS_PER_OI_INTERVAL - 1) / MSECS_PER_OI_INTERVAL)) + +/** + * Macro to convert minutes to OI_INTERVAL time units + */ + +#define OI_MINUTES(n) ((OI_INTERVAL) ((n) * OI_SECONDS(60))) + +/** Convert an OI_INTERVAL to milliseconds. */ +#define OI_INTERVAL_TO_MILLISECONDS(i) ((i) * MSECS_PER_OI_INTERVAL) + +/** + * The stack depends on relative not absolute time. Any mapping between the + * stack's real-time clock and absolute time and date is implementation-dependent. + */ + +typedef struct { + OI_INT32 seconds; + OI_INT16 mseconds; +} OI_TIME; + +/** + * Convert an OI_TIME to milliseconds. + * + * @param t the time to convert + * + * @return the time in milliseconds + */ +OI_UINT32 OI_Time_ToMS(OI_TIME *t); + + +/** + * This function compares two time values. + * + * @param T1 first time to compare. + * + * @param T2 second time to compare. + * + * @return + @verbatim + -1 if t1 < t2 + 0 if t1 = t2 + +1 if t1 > t2 + @endverbatim + */ + +OI_INT16 OI_Time_Compare(OI_TIME *T1, + OI_TIME *T2); + + +/** + * This function returns the interval between two times to a granularity of 0.1 seconds. + * + * @param Sooner a time value more recent that Later + * + * @param Later a time value later than Sooner + * + * @note The result is an OI_INTERVAL value so this function only works for time intervals + * that are less than about 71 minutes. + * + * @return the time interval between the two times = (Later - Sooner) + */ + +OI_INTERVAL OI_Time_Interval(OI_TIME *Sooner, + OI_TIME *Later); + + + +/** + * This function returns the interval between two times to a granularity of milliseconds. + * + * @param Sooner a time value more recent that Later + * + * @param Later a time value later than Sooner + * + * @note The result is an OI_UINT32 value so this function only works for time intervals + * that are less than about 50 days. + * + * @return the time interval between the two times = (Later - Sooner) + */ + +OI_UINT32 OI_Time_IntervalMsecs(OI_TIME *Sooner, + OI_TIME *Later); + + + +/** + * This function answers the question, Have we reached or gone past the target time? + * + * @param pTargetTime target time + * + * @return TRUE means time now is at or past target time + * FALSE means target time is still some time in the future + */ + +OI_BOOL OI_Time_NowReachedTime(OI_TIME *pTargetTime); + +/** + * Convert seconds to the Link Manager 1.28-second units + * Approximate by using 1.25 conversion factor. + */ + +#define OI_SECONDS_TO_LM_TIME_UNITS(lmUnits) ((lmUnits)<4?(lmUnits):(lmUnits)-((lmUnits)>>2)) + + +/** + * Convert Link Manager 1.28-second units to seconds. + * Approximate by using 1.25 conversion factor. + */ + +#define OI_LM_TIME_UNITS_TO_SECONDS(lmUnits) ((lmUnits) + ((lmUnits)>>2)) + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +/* Include for OI_Time_Now() prototype + * Must be included at end to obtain OI_TIME typedef + */ +#include "oi_osinterface.h" + +/*****************************************************************************/ +#endif /* _OI_TIME_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/include/oi_utils.h b/components/bt/bluedroid/external/sbc/decoder/include/oi_utils.h new file mode 100644 index 0000000000..f12ef0d4bc --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/include/oi_utils.h @@ -0,0 +1,377 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 _OI_UTILS_H +#define _OI_UTILS_H +/** + * @file + * + * This file provides the interface for utility functions. + * Among the utilities are strlen (string length), strcmp (string compare), and + * other string manipulation functions. These are provided for those plaforms + * where this functionality is not available in stdlib. + */ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +#include +#include "oi_common.h" +#include "oi_string.h" +#include "oi_bt_spec.h" + +/** \addtogroup Misc Miscellaneous APIs */ +/**@{*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Opaque type for a callback function handle. See OI_ScheduleCallbackFunction() + */ +typedef OI_UINT32 OI_CALLBACK_HANDLE; + + +/** + * Function prototype for a timed procedure callback. + * + * @param arg Value that was passed into the OI_ScheduleCallback() function + * + */ +typedef void (*OI_SCHEDULED_CALLBACK)(void *arg); + + +/** + * Registers a function to be called when a timeout expires. This API uses BLUEmagic's internal + * function dispatch mechanism, so applications that make extensive use of this facility may need to + * increase the value of DispatchTableSize in the configuration block for the dispatcher (see + * oi_bt_stack_config.h). + * + * @param callbackFunction The function that will be called when the timeout expires + * + * @param arg Value that will be returned as the parameter to the callback function. + * + * @param timeout A timeout expressed in OI_INTERVALs (tenths of seconds). This can be + * zero in which case the callback function will be called as soon as + * possible. + * + * @param handle NULL or a pointer receive the callback handle. + * + * @return OI_OK if the function was reqistered, or an error status. + */ +OI_STATUS OI_ScheduleCallbackFunction(OI_SCHEDULED_CALLBACK callbackFunction, + void *arg, + OI_INTERVAL timeout, + OI_CALLBACK_HANDLE *handle); + + +/** + * Cancels a function registered with OI_ScheduleCallbackFunction() before its timer expires. + * + * @param handle handle returned by OI_ScheduleCallbackFunction(). + * + * @return OI_OK if the function was cancelled, or an error status. + */ +OI_STATUS OI_CancelCallbackFunction(OI_CALLBACK_HANDLE handle); + + +/** + * Registers a function to be called when a timeout expires. This version does not return a handle + * so can only be canceled by calling OI_CancelCallback(). + * + * @param callbackFunction The function that will be called when the timeout expires + * + * @param arg Value that will be returned as the parameter to the callback function. + * + * @param timeout A timeout expressed in OI_INTERVALs (tenths of seconds). This can be + * zero in which case the callback function will be called as soon as + * possible. + * + * @return OI_OK if the function was reqistered, or an error status. + */ +#define OI_ScheduleCallback(f, a, t) OI_ScheduleCallbackFunction(f, a, t, NULL); + + +/** + * Cancels a function registered with OI_ScheduleCallback() before its timer expires. This + * function will cancel the first entry matches the indicated callback function pointer. + * + * @param callbackFunction The function that was originally registered + * + * @return OI_OK if the function was cancelled, or an error status. + */ +OI_STATUS OI_CancelCallback(OI_SCHEDULED_CALLBACK callbackFunction); + + +/** + * Parse a Bluetooth device address from the specified string. + * + * @param str the string to parse + * @param addr the parsed address, if successful + * + * @return TRUE if an address was successfully parsed, FALSE otherwise + */ + +OI_BOOL OI_ParseBdAddr(const OI_CHAR *str, + OI_BD_ADDR *addr) ; + +/** + * Printf function for platforms which have no stdio or printf available. + * OI_Printf supports the basic formatting types, with the exception of + * floating point types. Additionally, OI_Printf supports several formats + * specific to BLUEmagic 3.0 software: + * + * \%! prints the string for an #OI_STATUS value. + * @code OI_Printf("There was an error %!", status); @endcode + * + * \%@ prints a hex dump of a buffer. + * Requires a pointer to the buffer and a signed integer length + * (0 for default length). If the buffer is large, only an excerpt will + * be printed. + * @code OI_Printf("Contents of buffer %@", buffer, sizeof(buffer)); @endcode + * + * \%: prints a Bluetooth address in the form "HH:HH:HH:HH:HH:HH". + * Requires a pointer to an #OI_BD_ADDR. + * @code OI_Printf("Bluetooth address %:", &bdaddr); @endcode + * + * \%^ decodes and prints a data element as formatted XML. + * Requires a pointer to an #OI_DATAELEM. + * @code OI_Printf("Service attribute list is:\n%^", &attributes); @endcode + * + * \%/ prints the base file name of a path, that is, the final substring + * following a '/' or '\\' character. Requires a pointer to a null + * terminated string. + * @code OI_Printf("File %/", "c:\\dir1\\dir2\\file.txt"); @endcode + * + * \%~ prints a string, escaping characters as needed to display it in + * ASCII. Requires a pointer to an #OI_PSTR and an #OI_UNICODE_ENCODING + * parameter. + * @code OI_Printf("Identifier %~", &id, OI_UNICODE_UTF16_BE); @endcode + * + * \%[ inserts an ANSI color escape sequence. Requires a single character + * identifying the color to select. Colors are red (r/R), green (g/G), + * blue (b/B), yellow (y/Y), cyan (c/C), magenta (m/M), white (W), + * light-gray (l/L), dark-gray (d/D), and black (0). The lower case is + * dim, the upper case is bright (except in the case of light-gray and + * dark-gray, where bright and dim are identical). Any other value will + * select the default color. + * @code OI_Printf("%[red text %[black %[normal\n", 'r', '0', 0); @endcode + * + * \%a same as \%s, except '\\r' and '\\n' are output as "" and "". + * \%?a is valid, but \%la is not. + * + * \%b prints an integer in base 2. + * @code OI_Printf("Bits are %b", I); @endcode + * + * \%lb prints a long integer in base 2. + * + * \%?b prints the least significant N bits of an integer (or long integer) + * in base 2. Requires the integer and a length N. + * @code OI_Printf("Bottom 4 bits are: %?b", I, 4); @endcode + * + * \%B prints an integer as boolean text, "TRUE" or "FALSE". + * @code OI_Printf("The value 0 is %B, the value 1 is %B", 0, 1); @endcode + * + * \%?s prints a substring up to a specified maximum length. + * Requires a pointer to a string and a length parameter. + * @code OI_Printf("String prefix is %?s", str, 3); @endcode + * + * \%ls same as \%S. + * + * \%S prints a UTF16 string as UTF8 (plain ASCII, plus 8-bit char sequences + * where needed). Requires a pointer to #OI_CHAR16. \%?S is valid. The + * length parameter is in OI_CHAR16 characters. + * + * \%T prints time, formatted as "secs.msecs". + * Requires pointer to #OI_TIME struct, NULL pointer prints current time. + * @code OI_Printf("The time now is %T", NULL); @endcode + * + * @param format The format string + * + */ +void OI_Printf(const OI_CHAR *format, ...); + + +/** + * Var-args version OI_Printf + * + * @param format Same as for OI_Printf. + * + * @param argp Var-args list. + */ +void OI_VPrintf(const OI_CHAR *format, va_list argp); + + +/** + * Writes a formatted string to a buffer. This function supports the same format specifiers as + * OI_Printf(). + * + * @param buffer Destination buffer for the formatted string. + * + * @param bufLen The length of the destination buffer. + * + * @param format The format string + * + * @return Number of characters written or -1 in the case of an error. + */ +OI_INT32 OI_SNPrintf(OI_CHAR *buffer, + OI_UINT16 bufLen, + const OI_CHAR *format, ...); + + +/** + * Var-args version OI_SNPrintf + * + * @param buffer Destination buffer for the formatted string. + * + * @param bufLen The length of the destination buffer. + * + * @param format The format string + * + * @param argp Var-args list. + * + * @return Number of characters written or -1 in the case of an error. + */ +OI_INT32 OI_VSNPrintf(OI_CHAR *buffer, + OI_UINT16 bufLen, + const OI_CHAR *format, va_list argp); + + +/** + * Convert a string to an integer. + * + * @param str the string to parse + * + * @return the integer value of the string or 0 if the string could not be parsed + */ +OI_INT OI_atoi(const OI_CHAR *str); + + +/** + * Parse a signed integer in a string. + * + * Skips leading whitespace (space and tabs only) and parses a decimal or hex string. Hex string + * must be prefixed by "0x". Returns pointer to first character following the integer. Returns the + * pointer passed in if the string does not describe an integer. + * + * @param str String to parse. + * + * @param val Pointer to receive the parsed integer value. + * + * @return A pointer to the first character following the integer or the pointer passed in. + */ +const OI_CHAR *OI_ScanInt(const OI_CHAR *str, + OI_INT32 *val); + + +/** + * Parse an unsigned integer in a string. + * + * Skips leading whitespace (space and tabs only) and parses a decimal or hex string. Hex string + * must be prefixed by "0x". Returns pointer to first character following the integer. Returns the + * pointer passed in if the string does not describe an integer. + * + * @param str String to parse. + * + * @param val Pointer to receive the parsed unsigned integer value. + * + * @return A pointer to the first character following the unsigned integer or the pointer passed in. + */ +const OI_CHAR *OI_ScanUInt(const OI_CHAR *str, + OI_UINT32 *val); + +/** + * Parse a whitespace delimited substring out of a string. + * + * @param str Input string to parse. + * @param outStr Buffer to return the substring + * @param len Length of outStr + * + * + * @return A pointer to the first character following the substring or the pointer passed in. + */ +const OI_CHAR *OI_ScanStr(const OI_CHAR *str, + OI_CHAR *outStr, + OI_UINT16 len); + + +/** + * Parse a string for one of a set of alternative value. Skips leading whitespace (space and tabs + * only) and parses text matching one of the alternative strings. Returns pointer to first character + * following the matched text. + * + * @param str String to parse. + * + * @param alts Alternative matching strings separated by '|' + * + * @param index Pointer to receive the index of the matching alternative, return value is -1 if + * there is no match. + * + * @return A pointer to the first character following the matched value or the pointer passed in + * if there was no matching text. + */ +const OI_CHAR *OI_ScanAlt(const OI_CHAR *str, + const OI_CHAR *alts, + OI_INT *index); + +/** + * Parse a string for a BD Addr. Skips leading whitespace (space and tabs only) and parses a + * Bluetooth device address with nibbles optionally separated by colons. Return pointet to first + * character following the BD Addr. + * + * @param str String to parse. + * + * @param addr Pointer to receive the Bluetooth device address + * + * @return A pointer to the first character following the BD Addr or the pointer passed in. + */ +const OI_CHAR *OI_ScanBdAddr(const OI_CHAR *str, + OI_BD_ADDR *addr); + + +/** Get a character from a digit integer value (0 - 9). */ +#define OI_DigitToChar(d) ((d) + '0') + +/** + * Determine Maximum and Minimum between two arguments. + * + * @param a 1st value + * @param b 2nd value + * + * @return the max or min value between a & b + */ +#define OI_MAX(a, b) (((a) < (b)) ? (b) : (a) ) +#define OI_MIN(a, b) (((a) > (b)) ? (b) : (a) ) + +/** + * Compare two BD_ADDRs + * SAME_BD_ADDR - Boolean: TRUE if they are the same address + */ + +#define SAME_BD_ADDR(x, y) (0 == OI_MemCmp((x),(y),OI_BD_ADDR_BYTE_SIZE) ) + +#ifdef __cplusplus +} +#endif + +/**@}*/ + +#endif /* _OI_UTILS_H */ + diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/alloc.c b/components/bt/bluedroid/external/sbc/decoder/srce/alloc.c new file mode 100644 index 0000000000..4ed459d841 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/alloc.c @@ -0,0 +1,82 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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 "bt_target.h" +#include +#include + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +PRIVATE OI_STATUS OI_CODEC_SBC_Alloc(OI_CODEC_SBC_COMMON_CONTEXT *common, + OI_UINT32 *codecDataAligned, + OI_UINT32 codecDataBytes, + OI_UINT8 maxChannels, + OI_UINT8 pcmStride) +{ + int i; + size_t filterBufferCount; + size_t subdataSize; + OI_BYTE *codecData = (OI_BYTE *)codecDataAligned; + + if (maxChannels < 1 || maxChannels > 2) { + return OI_STATUS_INVALID_PARAMETERS; + } + + if (pcmStride < 1 || pcmStride > maxChannels) { + return OI_STATUS_INVALID_PARAMETERS; + } + + common->maxChannels = maxChannels; + common->pcmStride = pcmStride; + + /* Compute sizes needed for the memory regions, and bail if we don't have + * enough memory for them. */ + subdataSize = maxChannels * sizeof(common->subdata[0]) * SBC_MAX_BANDS * SBC_MAX_BLOCKS; + if (subdataSize > codecDataBytes) { + return OI_STATUS_OUT_OF_MEMORY; + } + + filterBufferCount = (codecDataBytes - subdataSize) / (sizeof(common->filterBuffer[0][0]) * SBC_MAX_BANDS * maxChannels); + if (filterBufferCount < SBC_CODEC_MIN_FILTER_BUFFERS) { + return OI_STATUS_OUT_OF_MEMORY; + } + common->filterBufferLen = filterBufferCount * SBC_MAX_BANDS; + + /* Allocate memory for the subband data */ + common->subdata = (OI_INT32 *)codecData; + codecData += subdataSize; + OI_ASSERT(codecDataBytes >= subdataSize); + codecDataBytes -= subdataSize; + + /* Allocate memory for the synthesis buffers */ + for (i = 0; i < maxChannels; ++i) { + size_t allocSize = common->filterBufferLen * sizeof(common->filterBuffer[0][0]); + common->filterBuffer[i] = (SBC_BUFFER_T *)codecData; + OI_ASSERT(codecDataBytes >= allocSize); + codecData += allocSize; + codecDataBytes -= allocSize; + } + + return OI_OK; +} + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c b/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c new file mode 100644 index 0000000000..bba67e079d --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc-sbc.c @@ -0,0 +1,168 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +/** @file +@ingroup codec_internal +*/ + +/**@addgroup codec_internal*/ +/**@{*/ +#include "bt_target.h" +#include + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +static void dualBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common) +{ + OI_UINT bitcountL; + OI_UINT bitcountR; + OI_UINT bitpoolPreferenceL = 0; + OI_UINT bitpoolPreferenceR = 0; + BITNEED_UNION1 bitneedsL; + BITNEED_UNION1 bitneedsR; + + bitcountL = computeBitneed(common, bitneedsL.uint8, 0, &bitpoolPreferenceL); + bitcountR = computeBitneed(common, bitneedsR.uint8, 1, &bitpoolPreferenceR); + + oneChannelBitAllocation(common, &bitneedsL, 0, bitcountL); + oneChannelBitAllocation(common, &bitneedsR, 1, bitcountR); +} + +static void stereoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common) +{ + const OI_UINT nrof_subbands = common->frameInfo.nrof_subbands; + BITNEED_UNION2 bitneeds; + OI_UINT excess; + OI_INT bitadjust; + OI_UINT bitcount; + OI_UINT sbL; + OI_UINT sbR; + OI_UINT bitpoolPreference = 0; + + bitcount = computeBitneed(common, &bitneeds.uint8[0], 0, &bitpoolPreference); + bitcount += computeBitneed(common, &bitneeds.uint8[nrof_subbands], 1, &bitpoolPreference); + + { + OI_UINT ex; + bitadjust = adjustToFitBitpool(common->frameInfo.bitpool, bitneeds.uint32, 2 * nrof_subbands, bitcount, &ex); + /* We want the compiler to put excess into a register */ + excess = ex; + } + sbL = 0; + sbR = nrof_subbands; + while (sbL < nrof_subbands) { + excess = allocAdjustedBits(&common->bits.uint8[sbL], bitneeds.uint8[sbL] + bitadjust, excess); + ++sbL; + excess = allocAdjustedBits(&common->bits.uint8[sbR], bitneeds.uint8[sbR] + bitadjust, excess); + ++sbR; + } + sbL = 0; + sbR = nrof_subbands; + while (excess) { + excess = allocExcessBits(&common->bits.uint8[sbL], excess); + ++sbL; + if (!excess) { + break; + } + excess = allocExcessBits(&common->bits.uint8[sbR], excess); + ++sbR; + } + +} + +static const BIT_ALLOC balloc[] = { + monoBitAllocation, /* SBC_MONO */ + dualBitAllocation, /* SBC_DUAL_CHANNEL */ + stereoBitAllocation, /* SBC_STEREO */ + stereoBitAllocation /* SBC_JOINT_STEREO */ +}; + + +PRIVATE void OI_SBC_ComputeBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common) +{ + OI_ASSERT(common->frameInfo.bitpool <= OI_SBC_MaxBitpool(&common->frameInfo)); + OI_ASSERT(common->frameInfo.mode < OI_ARRAYSIZE(balloc)); + + /* + * Using an array of function pointers prevents the compiler from creating a suboptimal + * monolithic inlined bit allocation function. + */ + balloc[common->frameInfo.mode](common); +} + +OI_UINT32 OI_CODEC_SBC_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame) +{ + return internal_CalculateBitrate(frame); +} + +/* + * Return the current maximum bitneed and clear it. + */ +OI_UINT8 OI_CODEC_SBC_GetMaxBitneed(OI_CODEC_SBC_COMMON_CONTEXT *common) +{ + OI_UINT8 max = common->maxBitneed; + + common->maxBitneed = 0; + return max; +} + +/* + * Calculates the bitpool size for a given frame length + */ +OI_UINT16 OI_CODEC_SBC_CalculateBitpool(OI_CODEC_SBC_FRAME_INFO *frame, + OI_UINT16 frameLen) +{ + OI_UINT16 nrof_subbands = frame->nrof_subbands; + OI_UINT16 nrof_blocks = frame->nrof_blocks; + OI_UINT16 hdr; + OI_UINT16 bits; + + if (frame->mode == SBC_JOINT_STEREO) { + hdr = 9 * nrof_subbands; + } else { + if (frame->mode == SBC_MONO) { + hdr = 4 * nrof_subbands; + } else { + hdr = 8 * nrof_subbands; + } + if (frame->mode == SBC_DUAL_CHANNEL) { + nrof_blocks *= 2; + } + } + bits = 8 * (frameLen - SBC_HEADER_LEN) - hdr; + return DIVIDE(bits, nrof_blocks); +} + +OI_UINT16 OI_CODEC_SBC_CalculatePcmBytes(OI_CODEC_SBC_COMMON_CONTEXT *common) +{ + return sizeof(OI_INT16) * common->pcmStride * common->frameInfo.nrof_subbands * common->frameInfo.nrof_blocks; +} + + +OI_UINT16 OI_CODEC_SBC_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame) +{ + return internal_CalculateFramelen(frame); +} + +/**@}*/ +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc.c b/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc.c new file mode 100644 index 0000000000..ce8156be80 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/bitalloc.c @@ -0,0 +1,405 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ + ***********************************************************************************/ + +/** +@file + +The functions in this file relate to the allocation of available bits to +subbands within the SBC/eSBC frame, along with support functions for computing +frame length and bitrate. + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +#include "bt_target.h" +#include "oi_utils.h" +#include + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +OI_UINT32 OI_SBC_MaxBitpool(OI_CODEC_SBC_FRAME_INFO *frame) +{ + switch (frame->mode) { + case SBC_MONO: + case SBC_DUAL_CHANNEL: + return 16 * frame->nrof_subbands; + case SBC_STEREO: + case SBC_JOINT_STEREO: + return 32 * frame->nrof_subbands; + } + + ERROR(("Invalid frame mode %d", frame->mode)); + OI_ASSERT(FALSE); + return 0; /* Should never be reached */ +} + + +PRIVATE OI_UINT16 internal_CalculateFramelen(OI_CODEC_SBC_FRAME_INFO *frame) +{ + OI_UINT16 nbits = frame->nrof_blocks * frame->bitpool; + OI_UINT16 nrof_subbands = frame->nrof_subbands; + OI_UINT16 result = nbits; + + if (frame->mode == SBC_JOINT_STEREO) { + result += nrof_subbands + (8 * nrof_subbands); + } else { + if (frame->mode == SBC_DUAL_CHANNEL) { + result += nbits; + } + if (frame->mode == SBC_MONO) { + result += 4 * nrof_subbands; + } else { + result += 8 * nrof_subbands; + } + } + return SBC_HEADER_LEN + (result + 7) / 8; +} + + +PRIVATE OI_UINT32 internal_CalculateBitrate(OI_CODEC_SBC_FRAME_INFO *frame) +{ + OI_UINT blocksbands; + blocksbands = frame->nrof_subbands * frame->nrof_blocks; + + return DIVIDE(8 * internal_CalculateFramelen(frame) * frame->frequency, blocksbands); +} + + +INLINE OI_UINT16 OI_SBC_CalculateFrameAndHeaderlen(OI_CODEC_SBC_FRAME_INFO *frame, OI_UINT *headerLen_) +{ + OI_UINT headerLen = SBC_HEADER_LEN + frame->nrof_subbands * frame->nrof_channels / 2; + + if (frame->mode == SBC_JOINT_STEREO) { + headerLen++; + } + + *headerLen_ = headerLen; + return internal_CalculateFramelen(frame); +} + + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + + +/* + * Computes the bit need for each sample and as also returns a counts of bit needs that are greater + * than one. This count is used in the first phase of bit allocation. + * + * We also compute a preferred bitpool value that this is the minimum bitpool needed to guarantee + * lossless representation of the audio data. The preferred bitpool may be larger than the bits + * actually required but the only input we have are the scale factors. For example, it takes 2 bits + * to represent values in the range -1 .. +1 but the scale factor is 0. To guarantee lossless + * representation we add 2 to each scale factor and sum them to come up with the preferred bitpool. + * This is not ideal because 0 requires 0 bits but we currently have no way of knowing this. + * + * @param bitneed Array to return bitneeds for each subband + * + * @param ch Channel 0 or 1 + * + * @param preferredBitpool Returns the number of reserved bits + * + * @return The SBC bit need + * + */ +OI_UINT computeBitneed(OI_CODEC_SBC_COMMON_CONTEXT *common, + OI_UINT8 *bitneeds, + OI_UINT ch, + OI_UINT *preferredBitpool) +{ + static const OI_INT8 offset4[4][4] = { + { -1, 0, 0, 0 }, + { -2, 0, 0, 1 }, + { -2, 0, 0, 1 }, + { -2, 0, 0, 1 } + }; + + static const OI_INT8 offset8[4][8] = { + { -2, 0, 0, 0, 0, 0, 0, 1 }, + { -3, 0, 0, 0, 0, 0, 1, 2 }, + { -4, 0, 0, 0, 0, 0, 1, 2 }, + { -4, 0, 0, 0, 0, 0, 1, 2 } + }; + + const OI_UINT nrof_subbands = common->frameInfo.nrof_subbands; + OI_UINT sb; + OI_INT8 *scale_factor = &common->scale_factor[ch ? nrof_subbands : 0]; + OI_UINT bitcount = 0; + OI_UINT8 maxBits = 0; + OI_UINT8 prefBits = 0; + + if (common->frameInfo.alloc == SBC_SNR) { + for (sb = 0; sb < nrof_subbands; sb++) { + OI_INT bits = scale_factor[sb]; + if (bits > maxBits) { + maxBits = bits; + } + if ((bitneeds[sb] = bits) > 1) { + bitcount += bits; + } + prefBits += 2 + bits; + } + } else { + const OI_INT8 *offset; + if (nrof_subbands == 4) { + offset = offset4[common->frameInfo.freqIndex]; + } else { + offset = offset8[common->frameInfo.freqIndex]; + } + for (sb = 0; sb < nrof_subbands; sb++) { + OI_INT bits = scale_factor[sb]; + if (bits > maxBits) { + maxBits = bits; + } + prefBits += 2 + bits; + if (bits) { + bits -= offset[sb]; + if (bits > 0) { + bits /= 2; + } + bits += 5; + } + if ((bitneeds[sb] = bits) > 1) { + bitcount += bits; + } + } + } + common->maxBitneed = OI_MAX(maxBits, common->maxBitneed); + *preferredBitpool += prefBits; + return bitcount; +} + + +/* + * Explanation of the adjustToFitBitpool inner loop. + * + * The inner loop computes the effect of adjusting the bit allocation up or + * down. Allocations must be 0 or in the range 2..16. This is accomplished by + * the following code: + * + * for (s = bands - 1; s >= 0; --s) { + * OI_INT bits = bitadjust + bitneeds[s]; + * bits = bits < 2 ? 0 : bits; + * bits = bits > 16 ? 16 : bits; + * count += bits; + * } + * + * This loop can be optimized to perform 4 operations at a time as follows: + * + * Adjustment is computed as a 7 bit signed value and added to the bitneed. + * + * Negative allocations are zeroed by masking. (n & 0x40) >> 6 puts the + * sign bit into bit 0, adding this to 0x7F give us a mask of 0x80 + * for -ve values and 0x7F for +ve values. + * + * n &= 0x7F + (n & 0x40) >> 6) + * + * Allocations greater than 16 are truncated to 16. Adjusted allocations are in + * the range 0..31 so we know that bit 4 indicates values >= 16. We use this bit + * to create a mask that zeroes bits 0 .. 3 if bit 4 is set. + * + * n &= (15 + (n >> 4)) + * + * Allocations of 1 are disallowed. Add and shift creates a mask that + * eliminates the illegal value + * + * n &= ((n + 14) >> 4) | 0x1E + * + * These operations can be performed in 8 bits without overflowing so we can + * operate on 4 values at once. + */ + + +/* + * Encoder/Decoder + * + * Computes adjustment +/- of bitneeds to fill bitpool and returns overall + * adjustment and excess bits. + * + * @param bitpool The bitpool we have to work within + * + * @param bitneeds An array of bit needs (more acturately allocation prioritities) for each + * subband across all blocks in the SBC frame + * + * @param subbands The number of subbands over which the adkustment is calculated. For mono and + * dual mode this is 4 or 8, for stereo or joint stereo this is 8 or 16. + * + * @param bitcount A starting point for the adjustment + * + * @param excess Returns the excess bits after the adjustment + * + * @return The adjustment. + */ +OI_INT adjustToFitBitpool(const OI_UINT bitpool, + OI_UINT32 *bitneeds, + const OI_UINT subbands, + OI_UINT bitcount, + OI_UINT *excess) +{ + OI_INT maxBitadjust = 0; + OI_INT bitadjust = (bitcount > bitpool) ? -8 : 8; + OI_INT chop = 8; + + /* + * This is essentially a binary search for the optimal adjustment value. + */ + while ((bitcount != bitpool) && chop) { + OI_UINT32 total = 0; + OI_UINT count; + OI_UINT32 adjust4; + OI_INT i; + + adjust4 = bitadjust & 0x7F; + adjust4 |= (adjust4 << 8); + adjust4 |= (adjust4 << 16); + + for (i = (subbands / 4 - 1); i >= 0; --i) { + OI_UINT32 mask; + OI_UINT32 n = bitneeds[i] + adjust4; + mask = 0x7F7F7F7F + ((n & 0x40404040) >> 6); + n &= mask; + mask = 0x0F0F0F0F + ((n & 0x10101010) >> 4); + n &= mask; + mask = (((n + 0x0E0E0E0E) >> 4) | 0x1E1E1E1E); + n &= mask; + total += n; + } + + count = (total & 0xFFFF) + (total >> 16); + count = (count & 0xFF) + (count >> 8); + + chop >>= 1; + if (count > bitpool) { + bitadjust -= chop; + } else { + maxBitadjust = bitadjust; + bitcount = count; + bitadjust += chop; + } + } + + *excess = bitpool - bitcount; + + return maxBitadjust; +} + + +/* + * The bit allocator trys to avoid single bit allocations except as a last resort. So in the case + * where a bitneed of 1 was passed over during the adsjustment phase 2 bits are now allocated. + */ +INLINE OI_INT allocAdjustedBits(OI_UINT8 *dest, + OI_INT bits, + OI_INT excess) +{ + if (bits < 16) { + if (bits > 1) { + if (excess) { + ++bits; + --excess; + } + } else if ((bits == 1) && (excess > 1)) { + bits = 2; + excess -= 2; + } else { + bits = 0; + } + } else { + bits = 16; + } + *dest = (OI_UINT8)bits; + return excess; +} + + +/* + * Excess bits not allocated by allocaAdjustedBits are allocated round-robin. + */ +INLINE OI_INT allocExcessBits(OI_UINT8 *dest, + OI_INT excess) +{ + if (*dest < 16) { + *dest += 1; + return excess - 1; + } else { + return excess; + } +} + +void oneChannelBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common, + BITNEED_UNION1 *bitneeds, + OI_UINT ch, + OI_UINT bitcount) +{ + const OI_UINT8 nrof_subbands = common->frameInfo.nrof_subbands; + OI_UINT excess; + OI_UINT sb; + OI_INT bitadjust; + OI_UINT8 RESTRICT *allocBits; + + + { + OI_UINT ex; + bitadjust = adjustToFitBitpool(common->frameInfo.bitpool, bitneeds->uint32, nrof_subbands, bitcount, &ex); + /* We want the compiler to put excess into a register */ + excess = ex; + } + + /* + * Allocate adjusted bits + */ + allocBits = &common->bits.uint8[ch ? nrof_subbands : 0]; + + sb = 0; + while (sb < nrof_subbands) { + excess = allocAdjustedBits(&allocBits[sb], bitneeds->uint8[sb] + bitadjust, excess); + ++sb; + } + sb = 0; + while (excess) { + excess = allocExcessBits(&allocBits[sb], excess); + ++sb; + } +} + + +void monoBitAllocation(OI_CODEC_SBC_COMMON_CONTEXT *common) +{ + BITNEED_UNION1 bitneeds; + OI_UINT bitcount; + OI_UINT bitpoolPreference = 0; + + bitcount = computeBitneed(common, bitneeds.uint8, 0, &bitpoolPreference); + + oneChannelBitAllocation(common, &bitneeds, 0, bitcount); +} + +/** +@} +*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/bitstream-decode.c b/components/bt/bluedroid/external/sbc/decoder/srce/bitstream-decode.c new file mode 100644 index 0000000000..743a7c1aa2 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/bitstream-decode.c @@ -0,0 +1,95 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +/** +@file +Functions for manipulating input bitstreams. + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +#include "bt_target.h" +#include "oi_stddefs.h" +#include "oi_bitstream.h" +#include "oi_assert.h" + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +PRIVATE void OI_BITSTREAM_ReadInit(OI_BITSTREAM *bs, + const OI_BYTE *buffer) +{ + bs->value = ((OI_INT32)buffer[0] << 16) | ((OI_INT32)buffer[1] << 8) | (buffer[2]); + bs->ptr.r = buffer + 3; + bs->bitPtr = 8; +} + +PRIVATE OI_UINT32 OI_BITSTREAM_ReadUINT(OI_BITSTREAM *bs, OI_UINT bits) +{ + OI_UINT32 result; + + OI_BITSTREAM_READUINT(result, bits, bs->ptr.r, bs->value, bs->bitPtr); + + return result; +} + +PRIVATE OI_UINT8 OI_BITSTREAM_ReadUINT4Aligned(OI_BITSTREAM *bs) +{ + OI_UINT32 result; + + OI_ASSERT(bs->bitPtr < 16); + OI_ASSERT(bs->bitPtr % 4 == 0); + + if (bs->bitPtr == 8) { + result = bs->value << 8; + bs->bitPtr = 12; + } else { + result = bs->value << 12; + bs->value = (bs->value << 8) | *bs->ptr.r++; + bs->bitPtr = 8; + } + result >>= 28; + OI_ASSERT(result < (1u << 4)); + return (OI_UINT8)result; +} + +PRIVATE OI_UINT8 OI_BITSTREAM_ReadUINT8Aligned(OI_BITSTREAM *bs) +{ + OI_UINT32 result; + OI_ASSERT(bs->bitPtr == 8); + + result = bs->value >> 16; + bs->value = (bs->value << 8) | *bs->ptr.r++; + + return (OI_UINT8)result; +} + +/** +@} +*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-oina.c b/components/bt/bluedroid/external/sbc/decoder/srce/decoder-oina.c new file mode 100644 index 0000000000..471864bd48 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/decoder-oina.c @@ -0,0 +1,141 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2006 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ + ***********************************************************************************/ + +/** +@file +This file exposes OINA-specific interfaces to decoder functions. + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +#include "bt_target.h" +#include + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +OI_STATUS OI_CODEC_SBC_DecoderConfigureRaw(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_BOOL enhanced, + OI_UINT8 frequency, + OI_UINT8 mode, + OI_UINT8 subbands, + OI_UINT8 blocks, + OI_UINT8 alloc, + OI_UINT8 maxBitpool) +{ + if (frequency > SBC_FREQ_48000) { + return OI_STATUS_INVALID_PARAMETERS; + } + + if (enhanced) { +#ifdef SBC_ENHANCED + if (subbands != SBC_SUBBANDS_8) { + return OI_STATUS_INVALID_PARAMETERS; + } +#else + return OI_STATUS_INVALID_PARAMETERS; +#endif + } + + if (mode > SBC_JOINT_STEREO) { + return OI_STATUS_INVALID_PARAMETERS; + } + + if (subbands > SBC_SUBBANDS_8) { + return OI_STATUS_INVALID_PARAMETERS; + } + + if (blocks > SBC_BLOCKS_16) { + return OI_STATUS_INVALID_PARAMETERS; + } + + if (alloc > SBC_SNR) { + return OI_STATUS_INVALID_PARAMETERS; + } + +#ifdef SBC_ENHANCED + context->common.frameInfo.enhanced = enhanced; +#else + context->common.frameInfo.enhanced = FALSE; +#endif + context->common.frameInfo.freqIndex = frequency; + context->common.frameInfo.mode = mode; + context->common.frameInfo.subbands = subbands; + context->common.frameInfo.blocks = blocks; + context->common.frameInfo.alloc = alloc; + context->common.frameInfo.bitpool = maxBitpool; + + OI_SBC_ExpandFrameFields(&context->common.frameInfo); + + if (context->common.frameInfo.nrof_channels >= context->common.pcmStride) { + return OI_STATUS_INVALID_PARAMETERS; + } + + return OI_OK; +} + + + +OI_STATUS OI_CODEC_SBC_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT8 bitpool, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes, + OI_INT16 *pcmData, + OI_UINT32 *pcmBytes) +{ + return internal_DecodeRaw(context, + bitpool, + frameData, + frameBytes, + pcmData, + pcmBytes); +} + +OI_STATUS OI_CODEC_SBC_DecoderLimit(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_BOOL enhanced, + OI_UINT8 subbands) +{ + if (enhanced) { +#ifdef SBC_ENHANCED + context->enhancedEnabled = TRUE; +#else + context->enhancedEnabled = FALSE; +#endif + } else { + context->enhancedEnabled = FALSE; + } + context->restrictSubbands = subbands; + context->limitFrameFormat = TRUE; + return OI_OK; +} + + +/** +@} +*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c b/components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c new file mode 100644 index 0000000000..09b8e5fa6e --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/decoder-private.c @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ + ***********************************************************************************/ + +/** +@file +This file drives SBC decoding. + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +#include "bt_target.h" +#include "oi_codec_sbc_private.h" +#include "oi_bitstream.h" +#include + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +OI_CHAR *const OI_Codec_Copyright = "Copyright 2002-2007 Open Interface North America, Inc. All rights reserved"; + +INLINE OI_STATUS internal_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT32 *decoderData, + OI_UINT32 decoderDataBytes, + OI_BYTE maxChannels, + OI_BYTE pcmStride, + OI_BOOL enhanced) +{ + OI_UINT i; + OI_STATUS status; + + for (i = 0; i < sizeof(*context); i++) { + ((char *)context)[i] = 0; + } + +#ifdef SBC_ENHANCED + context->enhancedEnabled = enhanced ? TRUE : FALSE; +#else + context->enhancedEnabled = FALSE; + if (enhanced) { + return OI_STATUS_INVALID_PARAMETERS; + } +#endif + + status = OI_CODEC_SBC_Alloc(&context->common, decoderData, decoderDataBytes, maxChannels, pcmStride); + + if (!OI_SUCCESS(status)) { + return status; + } + + context->common.codecInfo = OI_Codec_Copyright; + context->common.maxBitneed = 0; + context->limitFrameFormat = FALSE; + OI_SBC_ExpandFrameFields(&context->common.frameInfo); + + /*PLATFORM_DECODER_RESET(context);*/ + + return OI_OK; +} + + + + +/** + * Read the SBC header up to but not including the joint stereo mask. The syncword has already been + * examined, and the enhanced mode flag set, by FindSyncword. + */ +INLINE void OI_SBC_ReadHeader(OI_CODEC_SBC_COMMON_CONTEXT *common, const OI_BYTE *data) +{ + OI_CODEC_SBC_FRAME_INFO *frame = &common->frameInfo; + OI_UINT8 d1; + + + OI_ASSERT(data[0] == OI_SBC_SYNCWORD || data[0] == OI_SBC_ENHANCED_SYNCWORD); + + /* Avoid filling out all these strucutures if we already remember the values + * from last time. Just in case we get a stream corresponding to data[1] == + * 0, DecoderReset is responsible for ensuring the lookup table entries have + * already been populated + */ + d1 = data[1]; + if (d1 != frame->cachedInfo) { + + frame->freqIndex = (d1 & (BIT7 | BIT6)) >> 6; + frame->frequency = freq_values[frame->freqIndex]; + + frame->blocks = (d1 & (BIT5 | BIT4)) >> 4; + frame->nrof_blocks = block_values[frame->blocks]; + + frame->mode = (d1 & (BIT3 | BIT2)) >> 2; + frame->nrof_channels = channel_values[frame->mode]; + + frame->alloc = (d1 & BIT1) >> 1; + + frame->subbands = (d1 & BIT0); + frame->nrof_subbands = band_values[frame->subbands]; + + frame->cachedInfo = d1; + } + /* + * For decode, the bit allocator needs to know the bitpool value + */ + frame->bitpool = data[2]; + frame->crc = data[3]; +} + + +#define LOW(x) ((x)& 0xf) +#define HIGH(x) ((x) >> 4) + +/* + * Read scalefactor values and prepare the bitstream for OI_SBC_ReadSamples + */ +PRIVATE void OI_SBC_ReadScalefactors(OI_CODEC_SBC_COMMON_CONTEXT *common, + const OI_BYTE *b, + OI_BITSTREAM *bs) +{ + OI_UINT i = common->frameInfo.nrof_subbands * common->frameInfo.nrof_channels; + OI_INT8 *scale_factor = common->scale_factor; + OI_UINT f; + + if (common->frameInfo.nrof_subbands == 8 || common->frameInfo.mode != SBC_JOINT_STEREO) { + if (common->frameInfo.mode == SBC_JOINT_STEREO) { + common->frameInfo.join = *b++; + } else { + common->frameInfo.join = 0; + } + i /= 2; + do { + *scale_factor++ = HIGH(f = *b++); + *scale_factor++ = LOW(f); + } while (--i); + /* + * In this case we know that the scale factors end on a byte boundary so all we need to do + * is initialize the bitstream. + */ + OI_BITSTREAM_ReadInit(bs, b); + } else { + OI_ASSERT(common->frameInfo.nrof_subbands == 4 && common->frameInfo.mode == SBC_JOINT_STEREO); + common->frameInfo.join = HIGH(f = *b++); + i = (i - 1) / 2; + do { + *scale_factor++ = LOW(f); + *scale_factor++ = HIGH(f = *b++); + } while (--i); + *scale_factor++ = LOW(f); + /* + * In 4-subband joint stereo mode, the joint stereo information ends on a half-byte + * boundary, so it's necessary to use the bitstream abstraction to read it, since + * OI_SBC_ReadSamples will need to pick up in mid-byte. + */ + OI_BITSTREAM_ReadInit(bs, b); + *scale_factor++ = OI_BITSTREAM_ReadUINT4Aligned(bs); + } +} + +/** Read quantized subband samples from the input bitstream and expand them. */ +PRIVATE void OI_SBC_ReadSamples(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs) +{ + OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common; + OI_UINT nrof_blocks = common->frameInfo.nrof_blocks; + OI_INT32 *RESTRICT s = common->subdata; + OI_UINT8 *ptr = global_bs->ptr.w; + OI_UINT32 value = global_bs->value; + OI_UINT bitPtr = global_bs->bitPtr; + + const OI_UINT iter_count = common->frameInfo.nrof_channels * common->frameInfo.nrof_subbands / 4; + do { + OI_UINT i; + for (i = 0; i < iter_count; ++i) { + OI_UINT32 sf_by4 = ((OI_UINT32 *)common->scale_factor)[i]; + OI_UINT32 bits_by4 = common->bits.uint32[i]; + OI_UINT n; + for (n = 0; n < 4; ++n) { + OI_INT32 dequant; + OI_UINT bits; + OI_INT sf; + + if (OI_CPU_BYTE_ORDER == OI_LITTLE_ENDIAN_BYTE_ORDER) { + bits = bits_by4 & 0xFF; + bits_by4 >>= 8; + sf = sf_by4 & 0xFF; + sf_by4 >>= 8; + } else { + bits = (bits_by4 >> 24) & 0xFF; + bits_by4 <<= 8; + sf = (sf_by4 >> 24) & 0xFF; + sf_by4 <<= 8; + } + if (bits) { + OI_UINT32 raw; + OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr); + dequant = OI_SBC_Dequant(raw, sf, bits); + } else { + dequant = 0; + } + *s++ = dequant; + } + } + } while (--nrof_blocks); +} + +/** +@} +*/ +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c b/components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c new file mode 100644 index 0000000000..7dd29ed8f9 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/decoder-sbc.c @@ -0,0 +1,469 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2006 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ + ***********************************************************************************/ + +/** @file +@ingroup codec_internal +*/ + +/**@addtogroup codec_internal */ +/**@{*/ + +#include "bt_target.h" +#include "oi_codec_sbc_private.h" +#include "oi_bitstream.h" + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +#define SPECIALIZE_READ_SAMPLES_JOINT + +/** + * Scans through a buffer looking for a codec syncword. If the decoder has been + * set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search + * for both a standard and an enhanced syncword. + */ +PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT *context, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes) +{ +#ifdef SBC_ENHANCED + OI_BYTE search1 = OI_SBC_SYNCWORD; + OI_BYTE search2 = OI_SBC_ENHANCED_SYNCWORD; +#endif // SBC_ENHANCED + + if (*frameBytes == 0) { + return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; + } + +#ifdef SBC_ENHANCED + if (context->limitFrameFormat && context->enhancedEnabled) { + /* If the context is restricted, only search for specified SYNCWORD */ + search1 = search2; + } else if (context->enhancedEnabled == FALSE) { + /* If enhanced is not enabled, only search for classic SBC SYNCWORD*/ + search2 = search1; + } + while (*frameBytes && (**frameData != search1) && (**frameData != search2)) { + (*frameBytes)--; + (*frameData)++; + } + if (*frameBytes) { + /* Syncword found, *frameData points to it, and *frameBytes correctly + * reflects the number of bytes available to read, including the + * syncword. */ + context->common.frameInfo.enhanced = (**frameData == OI_SBC_ENHANCED_SYNCWORD); + return OI_OK; + } else { + /* No syncword was found anywhere in the provided input data. + * *frameData points past the end of the original input, and + * *frameBytes is 0. */ + return OI_CODEC_SBC_NO_SYNCWORD; + } +#else // SBC_ENHANCED + while (*frameBytes && (**frameData != OI_SBC_SYNCWORD)) { + (*frameBytes)--; + (*frameData)++; + } + if (*frameBytes) { + /* Syncword found, *frameData points to it, and *frameBytes correctly + * reflects the number of bytes available to read, including the + * syncword. */ + context->common.frameInfo.enhanced = FALSE; + return OI_OK; + } else { + /* No syncword was found anywhere in the provided input data. + * *frameData points past the end of the original input, and + * *frameBytes is 0. */ + return OI_CODEC_SBC_NO_SYNCWORD; + } +#endif // SBC_ENHANCED +} + +static OI_STATUS DecodeBody(OI_CODEC_SBC_DECODER_CONTEXT *context, + const OI_BYTE *bodyData, + OI_INT16 *pcmData, + OI_UINT32 *pcmBytes, + OI_BOOL allowPartial) +{ + OI_BITSTREAM bs; + OI_UINT frameSamples = context->common.frameInfo.nrof_blocks * context->common.frameInfo.nrof_subbands; + OI_UINT decode_block_count; + + /* + * Based on the header data, make sure that there is enough room to write the output samples. + */ + if (*pcmBytes < (sizeof(OI_INT16) * frameSamples * context->common.pcmStride) && !allowPartial) { + /* If we're not allowing partial decodes, we need room for the entire + * codec frame */ + TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA")); + return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA; + } else if (*pcmBytes < sizeof (OI_INT16) * context->common.frameInfo.nrof_subbands * context->common.pcmStride) { + /* Even if we're allowing partials, we can still only decode on a frame + * boundary */ + return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA; + } + + if (context->bufferedBlocks == 0) { + TRACE(("Reading scalefactors")); + OI_SBC_ReadScalefactors(&context->common, bodyData, &bs); + + TRACE(("Computing bit allocation")); + OI_SBC_ComputeBitAllocation(&context->common); + + TRACE(("Reading samples")); + if (context->common.frameInfo.mode == SBC_JOINT_STEREO) { + OI_SBC_ReadSamplesJoint(context, &bs); + } else { + OI_SBC_ReadSamples(context, &bs); + } + + context->bufferedBlocks = context->common.frameInfo.nrof_blocks; + } + + if (allowPartial) { + decode_block_count = *pcmBytes / sizeof(OI_INT16) / context->common.pcmStride / context->common.frameInfo.nrof_subbands; + + if (decode_block_count > context->bufferedBlocks) { + decode_block_count = context->bufferedBlocks; + } + + } else { + decode_block_count = context->common.frameInfo.nrof_blocks; + } + + TRACE(("Synthesizing frame")); + { + OI_UINT start_block = context->common.frameInfo.nrof_blocks - context->bufferedBlocks; + OI_SBC_SynthFrame(context, pcmData, start_block, decode_block_count); + } + + OI_ASSERT(context->bufferedBlocks >= decode_block_count); + context->bufferedBlocks -= decode_block_count; + + frameSamples = decode_block_count * context->common.frameInfo.nrof_subbands; + + /* + * When decoding mono into a stride-2 array, copy pcm data to second channel + */ + if (context->common.frameInfo.nrof_channels == 1 && context->common.pcmStride == 2) { + OI_UINT i; + for (i = 0; i < frameSamples; ++i) { + pcmData[2 * i + 1] = pcmData[2 * i]; + } + } + + /* + * Return number of pcm bytes generated by the decode operation. + */ + *pcmBytes = frameSamples * sizeof(OI_INT16) * context->common.pcmStride; + if (context->bufferedBlocks > 0) { + return OI_CODEC_SBC_PARTIAL_DECODE; + } else { + return OI_OK; + } +} + +PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT8 bitpool, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes, + OI_INT16 *pcmData, + OI_UINT32 *pcmBytes) +{ + OI_STATUS status; + OI_UINT bodyLen; + + TRACE(("+OI_CODEC_SBC_DecodeRaw")); + + if (context->bufferedBlocks == 0) { + /* + * The bitallocator needs to know the bitpool value. + */ + context->common.frameInfo.bitpool = bitpool; + /* + * Compute the frame length and check we have enough frame data to proceed + */ + bodyLen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo) - SBC_HEADER_LEN; + if (*frameBytes < bodyLen) { + TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA")); + return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA; + } + } else { + bodyLen = 0; + } + /* + * Decode the SBC data. Pass TRUE to DecodeBody to allow partial decoding of + * tones. + */ + status = DecodeBody(context, *frameData, pcmData, pcmBytes, TRUE); + if (OI_SUCCESS(status) || status == OI_CODEC_SBC_PARTIAL_DECODE) { + *frameData += bodyLen; + *frameBytes -= bodyLen; + } + TRACE(("-OI_CODEC_SBC_DecodeRaw: %d", status)); + return status; +} + +OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context, + OI_UINT32 *decoderData, + OI_UINT32 decoderDataBytes, + OI_UINT8 maxChannels, + OI_UINT8 pcmStride, + OI_BOOL enhanced) +{ + return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced); +} + +OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes, + OI_INT16 *pcmData, + OI_UINT32 *pcmBytes) +{ + OI_STATUS status; + OI_UINT framelen; + OI_UINT8 crc; + + TRACE(("+OI_CODEC_SBC_DecodeFrame")); + + TRACE(("Finding syncword")); + status = FindSyncword(context, frameData, frameBytes); + if (!OI_SUCCESS(status)) { + return status; + } + + /* Make sure enough data remains to read the header. */ + if (*frameBytes < SBC_HEADER_LEN) { + TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA")); + return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; + } + + TRACE(("Reading Header")); + OI_SBC_ReadHeader(&context->common, *frameData); + + /* + * Some implementations load the decoder into RAM and use overlays for 4 vs 8 subbands. We need + * to ensure that the SBC parameters for this frame are compatible with the restrictions imposed + * by the loaded overlays. + */ + if (context->limitFrameFormat && (context->common.frameInfo.subbands != context->restrictSubbands)) { + ERROR(("SBC parameters incompatible with loaded overlay")); + return OI_STATUS_INVALID_PARAMETERS; + } + + if (context->common.frameInfo.nrof_channels > context->common.maxChannels) { + ERROR(("SBC parameters incompatible with number of channels specified during reset")); + return OI_STATUS_INVALID_PARAMETERS; + } + + if (context->common.pcmStride < 1 || context->common.pcmStride > 2) { + ERROR(("PCM stride not set correctly during reset")); + return OI_STATUS_INVALID_PARAMETERS; + } + + /* + * At this point a header has been read. However, it's possible that we found a false syncword, + * so the header data might be invalid. Make sure we have enough bytes to read in the + * CRC-protected header, but don't require we have the whole frame. That way, if it turns out + * that we're acting on bogus header data, we don't stall the decoding process by waiting for + * data that we don't actually need. + */ + framelen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo); + if (*frameBytes < framelen) { + TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA")); + return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA; + } + + TRACE(("Calculating checksum")); + + crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData); + if (crc != context->common.frameInfo.crc) { + TRACE(("CRC Mismatch: calc=%02x read=%02x\n", crc, context->common.frameInfo.crc)); + TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_CHECKSUM_MISMATCH")); + return OI_CODEC_SBC_CHECKSUM_MISMATCH; + } + +#ifdef OI_DEBUG + /* + * Make sure the bitpool values are sane. + */ + if ((context->common.frameInfo.bitpool < SBC_MIN_BITPOOL) && !context->common.frameInfo.enhanced) { + ERROR(("Bitpool too small: %d (must be >= 2)", context->common.frameInfo.bitpool)); + return OI_STATUS_INVALID_PARAMETERS; + } + if (context->common.frameInfo.bitpool > OI_SBC_MaxBitpool(&context->common.frameInfo)) { + ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo))); + return OI_STATUS_INVALID_PARAMETERS; + } +#endif + + /* + * Now decode the SBC data. Partial decode is not yet implemented for an SBC + * stream, so pass FALSE to decode body to have it enforce the old rule that + * you have to decode a whole packet at a time. + */ + status = DecodeBody(context, *frameData + SBC_HEADER_LEN, pcmData, pcmBytes, FALSE); + if (OI_SUCCESS(status)) { + *frameData += framelen; + *frameBytes -= framelen; + } + TRACE(("-OI_CODEC_SBC_DecodeFrame: %d", status)); + + return status; +} + +OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, + const OI_BYTE **frameData, + OI_UINT32 *frameBytes) +{ + OI_STATUS status; + OI_UINT framelen; + OI_UINT headerlen; + OI_UINT8 crc; + + status = FindSyncword(context, frameData, frameBytes); + if (!OI_SUCCESS(status)) { + return status; + } + if (*frameBytes < SBC_HEADER_LEN) { + return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; + } + OI_SBC_ReadHeader(&context->common, *frameData); + framelen = OI_SBC_CalculateFrameAndHeaderlen(&context->common.frameInfo, &headerlen); + if (*frameBytes < headerlen) { + return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA; + } + crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData); + if (crc != context->common.frameInfo.crc) { + return OI_CODEC_SBC_CHECKSUM_MISMATCH; + } + if (*frameBytes < framelen) { + return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA; + } + context->bufferedBlocks = 0; + *frameData += framelen; + *frameBytes -= framelen; + return OI_OK; +} + +OI_UINT8 OI_CODEC_SBC_FrameCount(OI_BYTE *frameData, + OI_UINT32 frameBytes) +{ + OI_UINT8 mode; + OI_UINT8 blocks; + OI_UINT8 subbands; + OI_UINT8 frameCount = 0; + OI_UINT frameLen; + + while (frameBytes) { + while (frameBytes && ((frameData[0] & 0xFE) != 0x9C)) { + frameData++; + frameBytes--; + } + + if (frameBytes < SBC_HEADER_LEN) { + return frameCount; + } + + /* Extract and translate required fields from Header */ + subbands = mode = blocks = frameData[1];; + mode = (mode & (BIT3 | BIT2)) >> 2; + blocks = block_values[(blocks & (BIT5 | BIT4)) >> 4]; + subbands = band_values[(subbands & BIT0)]; + + /* Inline logic to avoid corrupting context */ + frameLen = blocks * frameData[2]; + switch (mode) { + case SBC_JOINT_STEREO: + frameLen += subbands + (8 * subbands); + break; + + case SBC_DUAL_CHANNEL: + frameLen *= 2; + /* fall through */ + + default: + if (mode == SBC_MONO) { + frameLen += 4 * subbands; + } else { + frameLen += 8 * subbands; + } + } + + frameCount++; + frameLen = SBC_HEADER_LEN + (frameLen + 7) / 8; + if (frameBytes > frameLen) { + frameBytes -= frameLen; + frameData += frameLen; + } else { + frameBytes = 0; + } + } + return frameCount; +} + +/** Read quantized subband samples from the input bitstream and expand them. */ + +#ifdef SPECIALIZE_READ_SAMPLES_JOINT + +PRIVATE void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs) +{ +#define NROF_SUBBANDS 4 +#include "readsamplesjoint.inc" +#undef NROF_SUBBANDS +} + +PRIVATE void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs) +{ +#define NROF_SUBBANDS 8 +#include "readsamplesjoint.inc" +#undef NROF_SUBBANDS +} + +typedef void (*READ_SAMPLES)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs); + +static const READ_SAMPLES SpecializedReadSamples[] = { + OI_SBC_ReadSamplesJoint4, + OI_SBC_ReadSamplesJoint8 +}; + +#endif /* SPECIALIZE_READ_SAMPLES_JOINT */ + + +PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs) +{ + OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common; + OI_UINT nrof_subbands = common->frameInfo.nrof_subbands; +#ifdef SPECIALIZE_READ_SAMPLES_JOINT + OI_ASSERT((nrof_subbands >> 3u) <= 1u); + SpecializedReadSamples[nrof_subbands >> 3](context, global_bs); +#else + +#define NROF_SUBBANDS nrof_subbands +#include "readsamplesjoint.inc" +#undef NROF_SUBBANDS +#endif /* SPECIALIZE_READ_SAMPLES_JOINT */ +} + +/**@}*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/dequant.c b/components/bt/bluedroid/external/sbc/decoder/srce/dequant.c new file mode 100644 index 0000000000..65c340a1ce --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/dequant.c @@ -0,0 +1,215 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +/** + @file + + Dequantizer for SBC decoder; reconstructs quantized representation of subband samples. + + @ingroup codec_internal + */ + +/** +@addtogroup codec_internal +@{ +*/ + +/** + This function is a fixed-point approximation of a modification of the following + dequantization operation defined in the spec, as inferred from section 12.6.4: + + @code + dequant = 2^(scale_factor+1) * ((raw * 2.0 + 1.0) / ((2^bits) - 1) - 1) + + 2 <= bits <= 16 + 0 <= raw < (2^bits)-1 (the -1 is because quantized values with all 1's are forbidden) + + -65535 < dequant < 65535 + @endcode + + The code below computes the dequantized value divided by a scaling constant + equal to about 1.38. This constant is chosen to ensure that the entry in the + dequant_long_scaled table for 16 bits is as accurate as possible, since it has + the least relative precision available to it due to its small magnitude. + + This routine outputs in Q16.15 format. + + The helper array dequant_long is defined as follows: + + @code + dequant_long_long[bits] = round(2^31 * 1/((2^bits - 1) / 1.38...) for 2 <= bits <= 16 + @endcode + + + Additionally, the table entries have the following property: + + @code + dequant_long_scaled[bits] <= 2^31 / ((2^bits - 1)) for 2 <= bits <= 16 + @endcode + + Therefore + + @code + d = 2 * raw + 1 1 <= d <= 2^bits - 2 + + d' = d * dequant_long[bits] + + d * dequant_long_scaled[bits] <= (2^bits - 2) * (2^31 / (2^bits - 1)) + d * dequant_long_scaled[bits] <= 2^31 * (2^bits - 2)/(2^bits - 1) < 2^31 + @endcode + + Therefore, d' doesn't overflow a signed 32-bit value. + + @code + + d' =~ 2^31 * (raw * 2.0 + 1.0) / (2^bits - 1) / 1.38... + + result = d' - 2^31/1.38... =~ 2^31 * ((raw * 2.0 + 1.0) / (2^bits - 1) - 1) / 1.38... + + result is therefore a scaled approximation to dequant. It remains only to + turn 2^31 into 2^(scale_factor+1). Since we're aiming for Q16.15 format, + this is achieved by shifting right by (15-scale_factor): + + (2^31 * x) >> (15-scale_factor) =~ 2^(31-15+scale_factor) * x = 2^15 * 2^(1+scale_factor) * x + @endcode + + */ + +#include "bt_target.h" +#include + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +#ifndef SBC_DEQUANT_LONG_SCALED_OFFSET +#define SBC_DEQUANT_LONG_SCALED_OFFSET 1555931970 +#endif + +#ifndef SBC_DEQUANT_LONG_UNSCALED_OFFSET +#define SBC_DEQUANT_LONG_UNSCALED_OFFSET 2147483648 +#endif + +#ifndef SBC_DEQUANT_SCALING_FACTOR +#define SBC_DEQUANT_SCALING_FACTOR 1.38019122262781f +#endif + +const OI_UINT32 dequant_long_scaled[17]; +const OI_UINT32 dequant_long_unscaled[17]; + +/** Scales x by y bits to the right, adding a rounding factor. + */ +#ifndef SCALE +#define SCALE(x, y) (((x) + (1 <<((y)-1))) >> (y)) +#endif + +#ifdef DEBUG_DEQUANTIZATION + +#include + +INLINE float dequant_float(OI_UINT32 raw, OI_UINT scale_factor, OI_UINT bits) +{ + float result = (1 << (scale_factor + 1)) * ((raw * 2.0f + 1.0f) / ((1 << bits) - 1.0f) - 1.0f); + + result /= SBC_DEQUANT_SCALING_FACTOR; + + /* Unless the encoder screwed up, all correct dequantized values should + * satisfy this inequality. Non-compliant encoders which generate quantized + * values with all 1-bits set can, theoretically, trigger this assert. This + * is unlikely, however, and only an issue in debug mode. + */ + OI_ASSERT(fabs(result) < 32768 * 1.6); + + return result; +} + +#endif + + +INLINE OI_INT32 OI_SBC_Dequant(OI_UINT32 raw, OI_UINT scale_factor, OI_UINT bits) +{ + OI_UINT32 d; + OI_INT32 result; + + OI_ASSERT(scale_factor <= 15); + OI_ASSERT(bits <= 16); + + if (bits <= 1) { + return 0; + } + + d = (raw * 2) + 1; + d *= dequant_long_scaled[bits]; + result = d - SBC_DEQUANT_LONG_SCALED_OFFSET; + +#ifdef DEBUG_DEQUANTIZATION + { + OI_INT32 integerized_float_result; + float float_result; + + float_result = dequant_float(raw, scale_factor, bits); + integerized_float_result = (OI_INT32)floor(0.5f + float_result * (1 << 15)); + + /* This detects overflow */ + OI_ASSERT(((result >= 0) && (integerized_float_result >= 0)) || + ((result <= 0) && (integerized_float_result <= 0))); + } +#endif + return result >> (15 - scale_factor); +} + +/* This version of Dequant does not incorporate the scaling factor of 1.38. It + * is intended for use with implementations of the filterbank which are + * hard-coded into a DSP. Output is Q16.4 format, so that after joint stereo + * processing (which leaves the most significant bit equal to the sign bit if + * the encoder is conformant) the result will fit a 24 bit fixed point signed + * value.*/ + +INLINE OI_INT32 OI_SBC_Dequant_Unscaled(OI_UINT32 raw, OI_UINT scale_factor, OI_UINT bits) +{ + OI_UINT32 d; + OI_INT32 result; + + OI_ASSERT(scale_factor <= 15); + OI_ASSERT(bits <= 16); + + + if (bits <= 1) { + return 0; + } + if (bits == 16) { + result = (raw << 16) + raw - 0x7fff7fff; + return SCALE(result, 24 - scale_factor); + } + + + d = (raw * 2) + 1; + d *= dequant_long_unscaled[bits]; + result = d - 0x80000000; + + return SCALE(result, 24 - scale_factor); +} + +/** +@} +*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/framing-sbc.c b/components/bt/bluedroid/external/sbc/decoder/srce/framing-sbc.c new file mode 100644 index 0000000000..7085c80848 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/framing-sbc.c @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +/** @file +@ingroup codec_internal +*/ + +/**@addgroup codec_internal*/ +/**@{*/ + +#include "bt_target.h" +#include "oi_codec_sbc_private.h" + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +const OI_CHAR *const OI_CODEC_SBC_FreqText[] = { "SBC_FREQ_16000", "SBC_FREQ_32000", "SBC_FREQ_44100", "SBC_FREQ_48000" }; +const OI_CHAR *const OI_CODEC_SBC_ModeText[] = { "SBC_MONO", "SBC_DUAL_CHANNEL", "SBC_STEREO", "SBC_JOINT_STEREO" }; +const OI_CHAR *const OI_CODEC_SBC_SubbandsText[] = { "SBC_SUBBANDS_4", "SBC_SUBBANDS_8" }; +const OI_CHAR *const OI_CODEC_SBC_BlocksText[] = { "SBC_BLOCKS_4", "SBC_BLOCKS_8", "SBC_BLOCKS_12", "SBC_BLOCKS_16" }; +const OI_CHAR *const OI_CODEC_SBC_AllocText[] = { "SBC_LOUDNESS", "SBC_SNR" }; + +#ifdef OI_DEBUG +void OI_CODEC_SBC_DumpConfig(OI_CODEC_SBC_FRAME_INFO *frameInfo) +{ + printf("SBC configuration\n"); + printf(" enhanced: %s\n", frameInfo->enhanced ? "TRUE" : "FALSE"); + printf(" frequency: %d\n", frameInfo->frequency); + printf(" subbands: %d\n", frameInfo->nrof_subbands); + printf(" blocks: %d\n", frameInfo->nrof_blocks); + printf(" channels: %d\n", frameInfo->nrof_channels); + printf(" mode: %s\n", OI_CODEC_SBC_ModeText[frameInfo->mode]); + printf(" alloc: %s\n", OI_CODEC_SBC_AllocText[frameInfo->alloc]); + printf(" bitpool: %d\n", frameInfo->bitpool); +} +#endif /* OI_DEBUG */ + +/**@}*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/framing.c b/components/bt/bluedroid/external/sbc/decoder/srce/framing.c new file mode 100644 index 0000000000..8d46cd5e1b --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/framing.c @@ -0,0 +1,253 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +/** +@file +Checksum and header-related functions. + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +#include "bt_target.h" +#include "oi_codec_sbc_private.h" +#include "oi_assert.h" + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +/* asdasd */ + +#define USE_NIBBLEWISE_CRC + +/* #define PRINT_SAMPLES */ +/* #define PRINT_SCALEFACTORS */ +/* #define DEBUG_CRC */ + +/* + * CRC-8 table for X^8 + X^4 + X^3 + X^2 + 1; byte-wise lookup + */ +#ifdef USE_WIDE_CRC +/* Save space if a char is 16 bits, such as on the C54x */ +const OI_BYTE crc8_wide[128] = { + 0x001d, 0x3a27, 0x7469, 0x4e53, 0xe8f5, 0xd2cf, 0x9c81, 0xa6bb, 0xcdd0, 0xf7ea, 0xb9a4, 0x839e, 0x2538, 0x1f02, 0x514c, 0x6b76, 0x879a, 0xbda0, 0xf3ee, 0xc9d4, 0x6f72, 0x5548, 0x1b06, 0x213c, 0x4a57, 0x706d, 0x3e23, 0x0419, 0xa2bf, 0x9885, 0xd6cb, 0xecf1, 0x130e, 0x2934, 0x677a, 0x5d40, 0xfbe6, 0xc1dc, 0x8f92, 0xb5a8, 0xdec3, 0xe4f9, 0xaab7, 0x908d, 0x362b, 0x0c11, 0x425f, 0x7865, 0x9489, 0xaeb3, 0xe0fd, 0xdac7, 0x7c61, 0x465b, 0x0815, 0x322f, 0x5944, 0x637e, 0x2d30, 0x170a, 0xb1ac, 0x8b96, 0xc5d8, 0xffe2, 0x263b, 0x1c01, 0x524f, 0x6875, 0xced3, 0xf4e9, 0xbaa7, 0x809d, 0xebf6, 0xd1cc, 0x9f82, 0xa5b8, 0x031e, 0x3924, 0x776a, 0x4d50, 0xa1bc, 0x9b86, 0xd5c8, 0xeff2, 0x4954, 0x736e, 0x3d20, 0x071a, 0x6c71, 0x564b, 0x1805, 0x223f, 0x8499, 0xbea3, 0xf0ed, 0xcad7, 0x3528, 0x0f12, 0x415c, 0x7b66, 0xddc0, 0xe7fa, 0xa9b4, 0x938e, 0xf8e5, 0xc2df, 0x8c91, 0xb6ab, 0x100d, 0x2a37, 0x6479, 0x5e43, 0xb2af, 0x8895, 0xc6db, 0xfce1, 0x5a47, 0x607d, 0x2e33, 0x1409, 0x7f62, 0x4558, 0x0b16, 0x312c, 0x978a, 0xadb0, 0xe3fe, 0xd9c4, +}; +#elif defined(USE_NIBBLEWISE_CRC) +const OI_BYTE crc8_narrow[16] = { + 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb +}; +#else +const OI_BYTE crc8_narrow[256] = { + 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53, 0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb, 0xcd, 0xd0, 0xf7, 0xea, 0xb9, 0xa4, 0x83, 0x9e, 0x25, 0x38, 0x1f, 0x02, 0x51, 0x4c, 0x6b, 0x76, 0x87, 0x9a, 0xbd, 0xa0, 0xf3, 0xee, 0xc9, 0xd4, 0x6f, 0x72, 0x55, 0x48, 0x1b, 0x06, 0x21, 0x3c, 0x4a, 0x57, 0x70, 0x6d, 0x3e, 0x23, 0x04, 0x19, 0xa2, 0xbf, 0x98, 0x85, 0xd6, 0xcb, 0xec, 0xf1, 0x13, 0x0e, 0x29, 0x34, 0x67, 0x7a, 0x5d, 0x40, 0xfb, 0xe6, 0xc1, 0xdc, 0x8f, 0x92, 0xb5, 0xa8, 0xde, 0xc3, 0xe4, 0xf9, 0xaa, 0xb7, 0x90, 0x8d, 0x36, 0x2b, 0x0c, 0x11, 0x42, 0x5f, 0x78, 0x65, 0x94, 0x89, 0xae, 0xb3, 0xe0, 0xfd, 0xda, 0xc7, 0x7c, 0x61, 0x46, 0x5b, 0x08, 0x15, 0x32, 0x2f, 0x59, 0x44, 0x63, 0x7e, 0x2d, 0x30, 0x17, 0x0a, 0xb1, 0xac, 0x8b, 0x96, 0xc5, 0xd8, 0xff, 0xe2, 0x26, 0x3b, 0x1c, 0x01, 0x52, 0x4f, 0x68, 0x75, 0xce, 0xd3, 0xf4, 0xe9, 0xba, 0xa7, 0x80, 0x9d, 0xeb, 0xf6, 0xd1, 0xcc, 0x9f, 0x82, 0xa5, 0xb8, 0x03, 0x1e, 0x39, 0x24, 0x77, 0x6a, 0x4d, 0x50, 0xa1, 0xbc, 0x9b, 0x86, 0xd5, 0xc8, 0xef, 0xf2, 0x49, 0x54, 0x73, 0x6e, 0x3d, 0x20, 0x07, 0x1a, 0x6c, 0x71, 0x56, 0x4b, 0x18, 0x05, 0x22, 0x3f, 0x84, 0x99, 0xbe, 0xa3, 0xf0, 0xed, 0xca, 0xd7, 0x35, 0x28, 0x0f, 0x12, 0x41, 0x5c, 0x7b, 0x66, 0xdd, 0xc0, 0xe7, 0xfa, 0xa9, 0xb4, 0x93, 0x8e, 0xf8, 0xe5, 0xc2, 0xdf, 0x8c, 0x91, 0xb6, 0xab, 0x10, 0x0d, 0x2a, 0x37, 0x64, 0x79, 0x5e, 0x43, 0xb2, 0xaf, 0x88, 0x95, 0xc6, 0xdb, 0xfc, 0xe1, 0x5a, 0x47, 0x60, 0x7d, 0x2e, 0x33, 0x14, 0x09, 0x7f, 0x62, 0x45, 0x58, 0x0b, 0x16, 0x31, 0x2c, 0x97, 0x8a, 0xad, 0xb0, 0xe3, 0xfe, 0xd9, 0xc4 +}; +#endif +const OI_UINT32 dequant_long_scaled[17] = { + 0, + 0, + 0x1ee9e116, /* bits=2 0.24151243 1/3 * (1/1.38019122262781) (0x00000008)*/ + 0x0d3fa99c, /* bits=3 0.10350533 1/7 * (1/1.38019122262781) (0x00000013)*/ + 0x062ec69e, /* bits=4 0.04830249 1/15 * (1/1.38019122262781) (0x00000029)*/ + 0x02fddbfa, /* bits=5 0.02337217 1/31 * (1/1.38019122262781) (0x00000055)*/ + 0x0178d9f5, /* bits=6 0.01150059 1/63 * (1/1.38019122262781) (0x000000ad)*/ + 0x00baf129, /* bits=7 0.00570502 1/127 * (1/1.38019122262781) (0x0000015e)*/ + 0x005d1abe, /* bits=8 0.00284132 1/255 * (1/1.38019122262781) (0x000002bf)*/ + 0x002e760d, /* bits=9 0.00141788 1/511 * (1/1.38019122262781) (0x00000582)*/ + 0x00173536, /* bits=10 0.00070825 1/1023 * (1/1.38019122262781) (0x00000b07)*/ + 0x000b9928, /* bits=11 0.00035395 1/2047 * (1/1.38019122262781) (0x00001612)*/ + 0x0005cc37, /* bits=12 0.00017693 1/4095 * (1/1.38019122262781) (0x00002c27)*/ + 0x0002e604, /* bits=13 0.00008846 1/8191 * (1/1.38019122262781) (0x00005852)*/ + 0x000172fc, /* bits=14 0.00004422 1/16383 * (1/1.38019122262781) (0x0000b0a7)*/ + 0x0000b97d, /* bits=15 0.00002211 1/32767 * (1/1.38019122262781) (0x00016150)*/ + 0x00005cbe, /* bits=16 0.00001106 1/65535 * (1/1.38019122262781) (0x0002c2a5)*/ +}; + + +const OI_UINT32 dequant_long_unscaled[17] = { + 0, + 0, + 0x2aaaaaab, /* bits=2 0.33333333 1/3 (0x00000005)*/ + 0x12492492, /* bits=3 0.14285714 1/7 (0x0000000e)*/ + 0x08888889, /* bits=4 0.06666667 1/15 (0x0000001d)*/ + 0x04210842, /* bits=5 0.03225806 1/31 (0x0000003e)*/ + 0x02082082, /* bits=6 0.01587302 1/63 (0x0000007e)*/ + 0x01020408, /* bits=7 0.00787402 1/127 (0x000000fe)*/ + 0x00808081, /* bits=8 0.00392157 1/255 (0x000001fd)*/ + 0x00402010, /* bits=9 0.00195695 1/511 (0x000003fe)*/ + 0x00200802, /* bits=10 0.00097752 1/1023 (0x000007fe)*/ + 0x00100200, /* bits=11 0.00048852 1/2047 (0x00000ffe)*/ + 0x00080080, /* bits=12 0.00024420 1/4095 (0x00001ffe)*/ + 0x00040020, /* bits=13 0.00012209 1/8191 (0x00003ffe)*/ + 0x00020008, /* bits=14 0.00006104 1/16383 (0x00007ffe)*/ + 0x00010002, /* bits=15 0.00003052 1/32767 (0x0000fffe)*/ + 0x00008001, /* bits=16 0.00001526 1/65535 (0x0001fffc)*/ +}; + +#if defined(OI_DEBUG) || defined(PRINT_SAMPLES) || defined(PRINT_SCALEFACTORS) +#include +#endif + +#ifdef USE_WIDE_CRC +INLINE OI_CHAR crc_iterate(OI_UINT8 oldcrc, OI_UINT8 next) +{ + OI_UINT crc; + OI_UINT idx; + idx = oldcrc ^ next; + crc = crc8_wide[idx >> 1]; + if (idx % 2) { + crc &= 0xff; + } else { + crc >>= 8; + } + + return crc; +} + +INLINE OI_CHAR crc_iterate_top4(OI_UINT8 oldcrc, OI_UINT8 next) +{ + OI_UINT crc; + OI_UINT idx; + idx = (oldcrc ^ next) >> 4; + crc = crc8_wide[idx >> 1]; + if (idx % 2) { + crc &= 0xff; + } else { + crc >>= 8; + } + + return (oldcrc << 4) ^ crc; +} + +#else // USE_WIDE_CRC + +INLINE OI_UINT8 crc_iterate_top4(OI_UINT8 oldcrc, OI_UINT8 next) +{ + return (oldcrc << 4) ^ crc8_narrow[(oldcrc ^ next) >> 4]; +} + +#ifdef USE_NIBBLEWISE_CRC +INLINE OI_UINT8 crc_iterate(OI_UINT8 crc, OI_UINT8 next) +{ + crc = (crc << 4) ^ crc8_narrow[(crc ^ next) >> 4]; + crc = (crc << 4) ^ crc8_narrow[((crc >> 4)^next) & 0xf]; + + return crc; +} + +#else // USE_NIBBLEWISE_CRC +INLINE OI_UINT8 crc_iterate(OI_UINT8 crc, OI_UINT8 next) +{ + return crc8_narrow[crc ^ next]; +} + +#endif // USE_NIBBLEWISE_CRC + +#endif // USE_WIDE_CRC + + +PRIVATE OI_UINT8 OI_SBC_CalculateChecksum(OI_CODEC_SBC_FRAME_INFO *frame, OI_BYTE const *data) +{ + OI_UINT i; + OI_UINT8 crc = 0x0f; + /* Count is the number of whole bytes subject to CRC. Actually, it's one + * more than this number, because data[3] is the CRC field itself, which is + * explicitly skipped. Since crc_iterate (should be) inlined, it's cheaper + * spacewise to include the check in the loop. This shouldn't be much of a + * bottleneck routine in the first place. */ + OI_UINT count = (frame->nrof_subbands * frame->nrof_channels / 2u) + 4; + + if (frame->mode == SBC_JOINT_STEREO && frame->nrof_subbands == 8) { + count++; + } + + for (i = 1; i < count; i++) { + if (i != 3) { + crc = crc_iterate(crc, data[i]); + } + } + + if (frame->mode == SBC_JOINT_STEREO && frame->nrof_subbands == 4) { + crc = crc_iterate_top4(crc, data[i]); + } + + return crc; +} + +void OI_SBC_ExpandFrameFields(OI_CODEC_SBC_FRAME_INFO *frame) +{ + frame->nrof_blocks = block_values[frame->blocks]; + frame->nrof_subbands = band_values[frame->subbands]; + + frame->frequency = freq_values[frame->freqIndex]; + frame->nrof_channels = channel_values[frame->mode]; +} + +/** + * Unrolled macro to copy 4 32-bit aligned 32-bit values backward in memory + */ +#define COPY4WORDS_BACK(_dest, _src) \ + do { \ + OI_INT32 _a, _b, _c, _d; \ + _a = *--_src; \ + _b = *--_src; \ + _c = *--_src; \ + _d = *--_src; \ + *--_dest = _a; \ + *--_dest = _b; \ + *--_dest = _c; \ + *--_dest = _d; \ + } while (0) + + +#if defined(USE_PLATFORM_MEMMOVE) || defined(USE_PLATFORM_MEMCPY) +#include +#endif +PRIVATE void shift_buffer(SBC_BUFFER_T *dest, SBC_BUFFER_T *src, OI_UINT wordCount) +{ +#ifdef USE_PLATFORM_MEMMOVE + memmove(dest, src, wordCount * sizeof(SBC_BUFFER_T)); +#elif defined(USE_PLATFORM_MEMCPY) + OI_ASSERT(((OI_CHAR *)(dest) - (OI_CHAR *)(src)) >= wordCount * sizeof(*dest)); + memcpy(dest, src, wordCount * sizeof(SBC_BUFFER_T)); +#else + OI_UINT n; + OI_INT32 *d; + OI_INT32 *s; + n = wordCount / 4 / (sizeof(OI_INT32) / sizeof(*dest)); + OI_ASSERT((n * 4 * (sizeof(OI_INT32) / sizeof(*dest))) == wordCount); + + d = (void *)(dest + wordCount); + s = (void *)(src + wordCount); + + do { + COPY4WORDS_BACK(d, s); + } while (--n); +#endif +} +/** +@} +*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/oi_codec_version.c b/components/bt/bluedroid/external/sbc/decoder/srce/oi_codec_version.c new file mode 100644 index 0000000000..1de00db185 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/oi_codec_version.c @@ -0,0 +1,61 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2002 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/** +@file +This file contains a single function, which returns a string indicating the +version number of the eSBC codec + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ +#include "bt_target.h" +#include "oi_stddefs.h" +#include "oi_codec_sbc_private.h" + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) +/** Version string for the BLUEmagic 3.0 protocol stack and profiles */ +PRIVATE OI_CHAR *const codecVersion = "v1.5" +#ifdef OI_SBC_EVAL + " (Evaluation version)" +#endif + ; + +/** This function returns the version string for the BLUEmagic 3.0 protocol stack + and profiles */ +OI_CHAR *OI_CODEC_Version(void) +{ + return codecVersion; +} + +/**********************************************************************************/ + +/** +@} +*/ + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc b/components/bt/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc new file mode 100644 index 0000000000..875a394975 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/readsamplesjoint.inc @@ -0,0 +1,111 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/******************************************************************************* + * @file readsamplesjoint.inc + * + * This is the body of the generic version of OI_SBC_ReadSamplesJoint(). + * It is designed to be \#included into a function as follows: + \code + void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs) + { + #define NROF_SUBBANDS 4 + #include "readsamplesjoint.inc" + #undef NROF_SUBBANDS + } + + void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs) + { + #define NROF_SUBBANDS 8 + #include "readsamplesjoint.inc" + #undef NROF_SUBBANDS + } + \endcode + * Or to make a generic version: + \code + void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_COMMON_CONTEXT *common, OI_BITSTREAM *global_bs) + { + OI_UINT nrof_subbands = common->frameInfo.nrof_subbands; + + #define NROF_SUBBANDS nrof_subbands + #include "readsamplesjoint.inc" + #undef NROF_SUBBANDS + } + \endcode + * @ingroup codec_internal + *******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +{ + OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common; + OI_UINT bl = common->frameInfo.nrof_blocks; + OI_INT32 * RESTRICT s = common->subdata; + OI_UINT8 *ptr = global_bs->ptr.w; + OI_UINT32 value = global_bs->value; + OI_UINT bitPtr = global_bs->bitPtr; + OI_UINT8 jmask = common->frameInfo.join << (8 - NROF_SUBBANDS); + + do { + OI_INT8 *sf_array = &common->scale_factor[0]; + OI_UINT8 *bits_array = &common->bits.uint8[0]; + OI_UINT8 joint = jmask; + OI_UINT sb; + /* + * Left channel + */ + sb = NROF_SUBBANDS; + do { + OI_UINT32 raw; + OI_INT32 dequant; + OI_UINT8 bits = *bits_array++; + OI_INT sf = *sf_array++; + + OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr); + dequant = OI_SBC_Dequant(raw, sf, bits); + *s++ = dequant; + } while (--sb); + /* + * Right channel + */ + sb = NROF_SUBBANDS; + do { + OI_UINT32 raw; + OI_INT32 dequant; + OI_UINT8 bits = *bits_array++; + OI_INT sf = *sf_array++; + + OI_BITSTREAM_READUINT(raw, bits, ptr, value, bitPtr); + dequant = OI_SBC_Dequant(raw, sf, bits); + /* + * Check if we need to do mid/side + */ + if (joint & 0x80) { + OI_INT32 mid = *(s - NROF_SUBBANDS); + OI_INT32 side = dequant; + *(s - NROF_SUBBANDS) = mid + side; + dequant = mid - side; + } + joint <<= 1; + *s++ = dequant; + } while (--sb); + } while (--bl); +} diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c b/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c new file mode 100644 index 0000000000..571cd4e03b --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-8-generated.c @@ -0,0 +1,139 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/** + @file + + DO NOT EDIT THIS FILE DIRECTLY + + This file is automatically generated by the "synthesis-gen.pl" script. + Any changes to this generated file will be lost when the script is re-run. + + These functions are called by functions in synthesis.c to perform the synthesis + filterbank computations for the SBC decoder. + + + */ +#include "bt_target.h" +#include + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +#ifndef CLIP_INT16 +#define CLIP_INT16(x) do { if (x > OI_INT16_MAX) { x = OI_INT16_MAX; } else if (x < OI_INT16_MIN) { x = OI_INT16_MIN; } } while (0) +#endif + +#define MUL_16S_16S(_x, _y) ((_x) * (_y)) + +PRIVATE void SynthWindow80_generated(OI_INT16 *pcm, SBC_BUFFER_T const *RESTRICT buffer, OI_UINT strideShift) +{ + OI_INT32 pcm_a, pcm_b; + /* 1 - stage 0 */ pcm_b = 0; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(8235, buffer[ 12])) >> 3; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(-23167, buffer[ 20])) >> 3; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(26479, buffer[ 28])) >> 2; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(-17397, buffer[ 36])) << 1; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(9399, buffer[ 44])) << 3; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(17397, buffer[ 52])) << 1; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(26479, buffer[ 60])) >> 2; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(23167, buffer[ 68])) >> 3; + /* 1 - stage 0 */ pcm_b += (MUL_16S_16S(8235, buffer[ 76])) >> 3; + /* 1 - stage 0 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[0 << strideShift] = (OI_INT16)pcm_b; + /* 1 - stage 1 */ pcm_a = 0; + /* 1 - stage 1 */ pcm_b = 0; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(-3263, buffer[ 5])) >> 5; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(9293, buffer[ 5])) >> 3; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(29293, buffer[ 11])) >> 5; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(-6087, buffer[ 11])) >> 2; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(-5229, buffer[ 21])); + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(1247, buffer[ 21])) << 3; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(30835, buffer[ 27])) >> 3; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(-2893, buffer[ 27])) << 3; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(-27021, buffer[ 37])) << 1; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(23671, buffer[ 37])) << 2; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(31633, buffer[ 43])) << 1; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(18055, buffer[ 43])) << 1; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(17319, buffer[ 53])) << 1; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(11537, buffer[ 53])) >> 1; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(26663, buffer[ 59])) >> 2; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(1747, buffer[ 59])) << 1; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(4555, buffer[ 69])) >> 1; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(685, buffer[ 69])) << 1; + /* 1 - stage 1 */ pcm_a += (MUL_16S_16S(12419, buffer[ 75])) >> 4; + /* 1 - stage 1 */ pcm_b += (MUL_16S_16S(8721, buffer[ 75])) >> 7; + /* 1 - stage 1 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[1 << strideShift] = (OI_INT16)pcm_a; + /* 1 - stage 1 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[7 << strideShift] = (OI_INT16)pcm_b; + /* 1 - stage 2 */ pcm_a = 0; + /* 1 - stage 2 */ pcm_b = 0; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(-10385, buffer[ 6])) >> 6; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(11167, buffer[ 6])) >> 4; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(24995, buffer[ 10])) >> 5; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(-10337, buffer[ 10])) >> 4; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(-309, buffer[ 22])) << 4; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(1917, buffer[ 22])) << 2; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(9161, buffer[ 26])) >> 3; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(-30605, buffer[ 26])) >> 1; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(-23063, buffer[ 38])) << 1; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(8317, buffer[ 38])) << 3; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(27561, buffer[ 42])) << 1; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(9553, buffer[ 42])) << 2; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(2309, buffer[ 54])) << 3; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(22117, buffer[ 54])) >> 4; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(12705, buffer[ 58])) >> 1; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(16383, buffer[ 58])) >> 2; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(6239, buffer[ 70])) >> 3; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(7543, buffer[ 70])) >> 3; + /* 1 - stage 2 */ pcm_a += (MUL_16S_16S(9251, buffer[ 74])) >> 4; + /* 1 - stage 2 */ pcm_b += (MUL_16S_16S(8603, buffer[ 74])) >> 6; + /* 1 - stage 2 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[2 << strideShift] = (OI_INT16)pcm_a; + /* 1 - stage 2 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[6 << strideShift] = (OI_INT16)pcm_b; + /* 1 - stage 3 */ pcm_a = 0; + /* 1 - stage 3 */ pcm_b = 0; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-16457, buffer[ 7])) >> 6; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(16913, buffer[ 7])) >> 5; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(19083, buffer[ 9])) >> 5; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(-8443, buffer[ 9])) >> 7; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-23641, buffer[ 23])) >> 2; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(3687, buffer[ 23])) << 1; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-29015, buffer[ 25])) >> 4; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(-301, buffer[ 25])) << 5; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(-12889, buffer[ 39])) << 2; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(15447, buffer[ 39])) << 2; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(6145, buffer[ 41])) << 3; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(10255, buffer[ 41])) << 2; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(24211, buffer[ 55])) >> 1; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(-18233, buffer[ 55])) >> 3; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(23469, buffer[ 57])) >> 2; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(9405, buffer[ 57])) >> 1; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(21223, buffer[ 71])) >> 8; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(1499, buffer[ 71])) >> 1; + /* 1 - stage 3 */ pcm_a += (MUL_16S_16S(26913, buffer[ 73])) >> 6; + /* 1 - stage 3 */ pcm_b += (MUL_16S_16S(26189, buffer[ 73])) >> 7; + /* 1 - stage 3 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[3 << strideShift] = (OI_INT16)pcm_a; + /* 1 - stage 3 */ pcm_b /= 32768; CLIP_INT16(pcm_b); pcm[5 << strideShift] = (OI_INT16)pcm_b; + /* 1 - stage 4 */ pcm_a = 0; + /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(10445, buffer[ 8])) >> 4; + /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(-5297, buffer[ 24])) << 1; + /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(22299, buffer[ 40])) << 2; + /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(10603, buffer[ 56])); + /* 1 - stage 4 */ pcm_a += (MUL_16S_16S(9539, buffer[ 72])) >> 4; + /* 1 - stage 4 */ pcm_a /= 32768; CLIP_INT16(pcm_a); pcm[4 << strideShift] = (OI_INT16)pcm_a; +} + +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c b/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c new file mode 100644 index 0000000000..a34032804c --- /dev/null +++ b/components/bt/bluedroid/external/sbc/decoder/srce/synthesis-dct8.c @@ -0,0 +1,308 @@ +/****************************************************************************** + * + * Copyright (C) 2014 The Android Open Source Project + * Copyright 2003 - 2004 Open Interface North America, Inc. All rights reserved. + * + * 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. + * + ******************************************************************************/ + +/********************************************************************************** + $Revision: #1 $ +***********************************************************************************/ + +/** @file +@ingroup codec_internal +*/ + +/**@addgroup codec_internal*/ +/**@{*/ + +/* + * Performs an 8-point Type-II scaled DCT using the Arai-Agui-Nakajima + * factorization. The scaling factors are folded into the windowing + * constants. 29 adds and 5 16x32 multiplies per 8 samples. + */ +#include "bt_target.h" +#include "oi_codec_sbc_private.h" + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +#define AAN_C4_FIX (759250125)/* S1.30 759250125 0.707107*/ + +#define AAN_C6_FIX (410903207)/* S1.30 410903207 0.382683*/ + +#define AAN_Q0_FIX (581104888)/* S1.30 581104888 0.541196*/ + +#define AAN_Q1_FIX (1402911301)/* S1.30 1402911301 1.306563*/ + +/** Scales x by y bits to the right, adding a rounding factor. + */ +#ifndef SCALE +#define SCALE(x, y) (((x) + (1 <<((y)-1))) >> (y)) +#endif + +/** + * Default C language implementation of a 32x32->32 multiply. This function may + * be replaced by a platform-specific version for speed. + * + * @param u A signed 32-bit multiplicand + * @param v A signed 32-bit multiplier + + * @return A signed 32-bit value corresponding to the 32 most significant bits + * of the 64-bit product of u and v. + */ +INLINE OI_INT32 default_mul_32s_32s_hi(OI_INT32 u, OI_INT32 v) +{ + OI_UINT32 u0, v0; + OI_INT32 u1, v1, w1, w2, t; + + u0 = u & 0xFFFF; u1 = u >> 16; + v0 = v & 0xFFFF; v1 = v >> 16; + t = u0 * v0; + t = u1 * v0 + ((OI_UINT32)t >> 16); + w1 = t & 0xFFFF; + w2 = t >> 16; + w1 = u0 * v1 + w1; + return u1 * v1 + w2 + (w1 >> 16); +} + +#define MUL_32S_32S_HI(_x, _y) default_mul_32s_32s_hi(_x, _y) + + +#ifdef DEBUG_DCT +PRIVATE void float_dct2_8(float *RESTRICT out, OI_INT32 const *RESTRICT in) +{ +#define FIX(x,bits) (((int)floor(0.5f+((x)*((float)(1<= 8 ? 16 : 0) + and VSIGN(i) maps i%16 into {1, 1, 1, 1, 0, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1 } + These values correspond to the + signs of the redundant values as + shown in the explanation three + paragraphs above. +@endcode + +We saw above how V[4..8,13..15] (and by extension +V[(4..8,13..15)+16*n]) can be defined in terms of other elements +within the subblock of V. V[0..3,9..12] correspond to DCT elements. + +@code + for i=0 to 79 do + W[i] = D[i]*DSIGN(i)*DCT[remap_DCT(i)] +@endcode + +The DCT is calculated using the Arai-Agui-Nakajima factorization, +which saves some computation by producing output that needs to be +multiplied by scaling factors before being used. + +@code + for i=0 to 79 do + W[i] = D[i]*SCALE[i%8]*AAN_DCT[remap_DCT(i)] +@endcode + +D can be premultiplied with the DCT scaling factors to yield + +@code + for i=0 to 79 do + W[i] = DSCALED[i]*AAN_DCT[remap_DCT(i)] where DSCALED[i] = D[i]*SCALE[i%8] +@endcode + +The output samples X[0..7] are defined as sums of W: + +@code + X[j] = sum{i=0..9}(W[j+8*i]) +@endcode + +@ingroup codec_internal +*/ + +/** +@addtogroup codec_internal +@{ +*/ +#include "bt_target.h" +#include "oi_codec_sbc_private.h" + +#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) + +const OI_INT32 dec_window_4[21] = { + 0, /* +0.00000000E+00 */ + 97, /* +5.36548976E-04 */ + 270, /* +1.49188357E-03 */ + 495, /* +2.73370904E-03 */ + 694, /* +3.83720193E-03 */ + 704, /* +3.89205149E-03 */ + 338, /* +1.86581691E-03 */ + -554, /* -3.06012286E-03 */ + 1974, /* +1.09137620E-02 */ + 3697, /* +2.04385087E-02 */ + 5224, /* +2.88757392E-02 */ + 5824, /* +3.21939290E-02 */ + 4681, /* +2.58767811E-02 */ + 1109, /* +6.13245186E-03 */ + -5214, /* -2.88217274E-02 */ + -14047, /* -7.76463494E-02 */ + 24529, /* +1.35593274E-01 */ + 35274, /* +1.94987841E-01 */ + 44618, /* +2.46636662E-01 */ + 50984, /* +2.81828203E-01 */ + 53243, /* +2.94315332E-01 */ +}; + +#define DCTII_4_K06_FIX ( 11585)/* S1.14 11585 0.707107*/ + +#define DCTII_4_K08_FIX ( 21407)/* S1.14 21407 1.306563*/ + +#define DCTII_4_K09_FIX (-15137)/* S1.14 -15137 -0.923880*/ + +#define DCTII_4_K10_FIX ( -8867)/* S1.14 -8867 -0.541196*/ + +/** Scales x by y bits to the right, adding a rounding factor. + */ +#ifndef SCALE +#define SCALE(x, y) (((x) + (1 <<((y)-1))) >> (y)) +#endif + +#ifndef CLIP_INT16 +#define CLIP_INT16(x) do { if (x > OI_INT16_MAX) { x = OI_INT16_MAX; } else if (x < OI_INT16_MIN) { x = OI_INT16_MIN; } } while (0) +#endif + +/** + * Default C language implementation of a 16x32->32 multiply. This function may + * be replaced by a platform-specific version for speed. + * + * @param u A signed 16-bit multiplicand + * @param v A signed 32-bit multiplier + + * @return A signed 32-bit value corresponding to the 32 most significant bits + * of the 48-bit product of u and v. + */ +INLINE OI_INT32 default_mul_16s_32s_hi(OI_INT16 u, OI_INT32 v) +{ + OI_UINT16 v0; + OI_INT16 v1; + + OI_INT32 w, x; + + v0 = (OI_UINT16)(v & 0xffff); + v1 = (OI_INT16) (v >> 16); + + w = v1 * u; + x = u * v0; + + return w + (x >> 16); +} + +#define MUL_16S_32S_HI(_x, _y) default_mul_16s_32s_hi(_x, _y) + +#define LONG_MULT_DCT(K, sample) (MUL_16S_32S_HI(K, sample)<<2) + +PRIVATE void SynthWindow80_generated(OI_INT16 *pcm, SBC_BUFFER_T const *RESTRICT buffer, OI_UINT strideShift); +PRIVATE void SynthWindow112_generated(OI_INT16 *pcm, SBC_BUFFER_T const *RESTRICT buffer, OI_UINT strideShift); +PRIVATE void dct2_8(SBC_BUFFER_T *RESTRICT out, OI_INT32 const *RESTRICT x); + +typedef void (*SYNTH_FRAME)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount); + +#ifndef COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS +#define COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(dest, src) do { shift_buffer(dest, src, 72); } while (0) +#endif + +#ifndef DCT2_8 +#define DCT2_8(dst, src) dct2_8(dst, src) +#endif + +#ifndef SYNTH80 +#define SYNTH80 SynthWindow80_generated +#endif + +#ifndef SYNTH112 +#define SYNTH112 SynthWindow112_generated +#endif + +PRIVATE void OI_SBC_SynthFrame_80(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount) +{ + OI_UINT blk; + OI_UINT ch; + OI_UINT nrof_channels = context->common.frameInfo.nrof_channels; + OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1; + OI_UINT offset = context->common.filterBufferOffset; + OI_INT32 *s = context->common.subdata + 8 * nrof_channels * blkstart; + OI_UINT blkstop = blkstart + blkcount; + + for (blk = blkstart; blk < blkstop; blk++) { + if (offset == 0) { + COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[0] + context->common.filterBufferLen - 72, context->common.filterBuffer[0]); + if (nrof_channels == 2) { + COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 72, context->common.filterBuffer[1]); + } + offset = context->common.filterBufferLen - 80; + } else { + offset -= 1 * 8; + } + + for (ch = 0; ch < nrof_channels; ch++) { + DCT2_8(context->common.filterBuffer[ch] + offset, s); + SYNTH80(pcm + ch, context->common.filterBuffer[ch] + offset, pcmStrideShift); + s += 8; + } + pcm += (8 << pcmStrideShift); + } + context->common.filterBufferOffset = offset; +} + +PRIVATE void OI_SBC_SynthFrame_4SB(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount) +{ + OI_UINT blk; + OI_UINT ch; + OI_UINT nrof_channels = context->common.frameInfo.nrof_channels; + OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1; + OI_UINT offset = context->common.filterBufferOffset; + OI_INT32 *s = context->common.subdata + 8 * nrof_channels * blkstart; + OI_UINT blkstop = blkstart + blkcount; + + for (blk = blkstart; blk < blkstop; blk++) { + if (offset == 0) { + COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[0] + context->common.filterBufferLen - 72, context->common.filterBuffer[0]); + if (nrof_channels == 2) { + COPY_BACKWARD_32BIT_ALIGNED_72_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 72, context->common.filterBuffer[1]); + } + offset = context->common.filterBufferLen - 80; + } else { + offset -= 8; + } + for (ch = 0; ch < nrof_channels; ch++) { + cosineModulateSynth4(context->common.filterBuffer[ch] + offset, s); + SynthWindow40_int32_int32_symmetry_with_sum(pcm + ch, + context->common.filterBuffer[ch] + offset, + pcmStrideShift); + s += 4; + } + pcm += (4 << pcmStrideShift); + } + context->common.filterBufferOffset = offset; +} + +#ifdef SBC_ENHANCED + +PRIVATE void OI_SBC_SynthFrame_Enhanced(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT blkstart, OI_UINT blkcount) +{ + OI_UINT blk; + OI_UINT ch; + OI_UINT nrof_channels = context->common.frameInfo.nrof_channels; + OI_UINT pcmStrideShift = context->common.pcmStride == 1 ? 0 : 1; + OI_UINT offset = context->common.filterBufferOffset; + OI_INT32 *s = context->common.subdata + 8 * nrof_channels * blkstart; + OI_UINT blkstop = blkstart + blkcount; + + for (blk = blkstart; blk < blkstop; blk++) { + if (offset == 0) { + COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(context->common.filterBuffer[0] + context->common.filterBufferLen - 104, context->common.filterBuffer[0]); + if (nrof_channels == 2) { + COPY_BACKWARD_32BIT_ALIGNED_104_HALFWORDS(context->common.filterBuffer[1] + context->common.filterBufferLen - 104, context->common.filterBuffer[1]); + } + offset = context->common.filterBufferLen - 112; + } else { + offset -= 8; + } + for (ch = 0; ch < nrof_channels; ++ch) { + DCT2_8(context->common.filterBuffer[ch] + offset, s); + SYNTH112(pcm + ch, context->common.filterBuffer[ch] + offset, pcmStrideShift); + s += 8; + } + pcm += (8 << pcmStrideShift); + } + context->common.filterBufferOffset = offset; +} + +static const SYNTH_FRAME SynthFrameEnhanced[] = { + NULL, /* invalid */ + OI_SBC_SynthFrame_Enhanced, /* mono */ + OI_SBC_SynthFrame_Enhanced /* stereo */ +}; + +#endif + +static const SYNTH_FRAME SynthFrame8SB[] = { + NULL, /* invalid */ + OI_SBC_SynthFrame_80, /* mono */ + OI_SBC_SynthFrame_80 /* stereo */ +}; + + +static const SYNTH_FRAME SynthFrame4SB[] = { + NULL, /* invalid */ + OI_SBC_SynthFrame_4SB, /* mono */ + OI_SBC_SynthFrame_4SB /* stereo */ +}; + +PRIVATE void OI_SBC_SynthFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_INT16 *pcm, OI_UINT start_block, OI_UINT nrof_blocks) +{ + OI_UINT nrof_subbands = context->common.frameInfo.nrof_subbands; + OI_UINT nrof_channels = context->common.frameInfo.nrof_channels; + + OI_ASSERT(nrof_subbands == 4 || nrof_subbands == 8); + if (nrof_subbands == 4) { + SynthFrame4SB[nrof_channels](context, pcm, start_block, nrof_blocks); +#ifdef SBC_ENHANCED + } else if (context->common.frameInfo.enhanced) { + SynthFrameEnhanced[nrof_channels](context, pcm, start_block, nrof_blocks); +#endif /* SBC_ENHANCED */ + } else { + SynthFrame8SB[nrof_channels](context, pcm, start_block, nrof_blocks); + } +} + + +void SynthWindow40_int32_int32_symmetry_with_sum(OI_INT16 *pcm, SBC_BUFFER_T buffer[80], OI_UINT strideShift) +{ + OI_INT32 pa; + OI_INT32 pb; + + /* These values should be zero, since out[2] of the 4-band cosine modulation + * is always zero. */ + OI_ASSERT(buffer[ 2] == 0); + OI_ASSERT(buffer[10] == 0); + OI_ASSERT(buffer[18] == 0); + OI_ASSERT(buffer[26] == 0); + OI_ASSERT(buffer[34] == 0); + OI_ASSERT(buffer[42] == 0); + OI_ASSERT(buffer[50] == 0); + OI_ASSERT(buffer[58] == 0); + OI_ASSERT(buffer[66] == 0); + OI_ASSERT(buffer[74] == 0); + + + pa = dec_window_4[ 4] * (buffer[12] + buffer[76]); + pa += dec_window_4[ 8] * (buffer[16] - buffer[64]); + pa += dec_window_4[12] * (buffer[28] + buffer[60]); + pa += dec_window_4[16] * (buffer[32] - buffer[48]); + pa += dec_window_4[20] * buffer[44]; + pa = SCALE(-pa, 15); + CLIP_INT16(pa); + pcm[0 << strideShift] = (OI_INT16)pa; + + + pa = dec_window_4[ 1] * buffer[ 1]; pb = dec_window_4[ 1] * buffer[79]; + pb += dec_window_4[ 3] * buffer[ 3]; pa += dec_window_4[ 3] * buffer[77]; + pa += dec_window_4[ 5] * buffer[13]; pb += dec_window_4[ 5] * buffer[67]; + pb += dec_window_4[ 7] * buffer[15]; pa += dec_window_4[ 7] * buffer[65]; + pa += dec_window_4[ 9] * buffer[17]; pb += dec_window_4[ 9] * buffer[63]; + pb += dec_window_4[11] * buffer[19]; pa += dec_window_4[11] * buffer[61]; + pa += dec_window_4[13] * buffer[29]; pb += dec_window_4[13] * buffer[51]; + pb += dec_window_4[15] * buffer[31]; pa += dec_window_4[15] * buffer[49]; + pa += dec_window_4[17] * buffer[33]; pb += dec_window_4[17] * buffer[47]; + pb += dec_window_4[19] * buffer[35]; pa += dec_window_4[19] * buffer[45]; + pa = SCALE(-pa, 15); + CLIP_INT16(pa); + pcm[1 << strideShift] = (OI_INT16)(pa); + pb = SCALE(-pb, 15); + CLIP_INT16(pb); + pcm[3 << strideShift] = (OI_INT16)(pb); + + + pa = dec_window_4[2] * (/*buffer[ 2] + */ buffer[78]); /* buffer[ 2] is always zero */ + pa += dec_window_4[6] * (buffer[14] /* + buffer[66]*/); /* buffer[66] is always zero */ + pa += dec_window_4[10] * (/*buffer[18] + */ buffer[62]); /* buffer[18] is always zero */ + pa += dec_window_4[14] * (buffer[30] /* + buffer[50]*/); /* buffer[50] is always zero */ + pa += dec_window_4[18] * (/*buffer[34] + */ buffer[46]); /* buffer[34] is always zero */ + pa = SCALE(-pa, 15); + CLIP_INT16(pa); + pcm[2 << strideShift] = (OI_INT16)(pa); +} + + +/** + This routine implements the cosine modulation matrix for 4-subband + synthesis. This is called "matrixing" in the SBC specification. This + matrix, M4, can be factored into an 8-point Type II Discrete Cosine + Transform, DCTII_4 and a matrix S4, given here: + + @code + __ __ + | 0 0 1 0 | + | 0 0 0 1 | + | 0 0 0 0 | + | 0 0 0 -1 | + S4 = | 0 0 -1 0 | + | 0 -1 0 0 | + | -1 0 0 0 | + |__ 0 -1 0 0 __| + + M4 * in = S4 * (DCTII_4 * in) + @endcode + + (DCTII_4 * in) is computed using a Fast Cosine Transform. The algorithm + here is based on an implementation computed by the SPIRAL computer + algebra system, manually converted to fixed-point arithmetic. S4 can be + implemented using only assignment and negation. + */ +PRIVATE void cosineModulateSynth4(SBC_BUFFER_T *RESTRICT out, OI_INT32 const *RESTRICT in) +{ + OI_INT32 f0, f1, f2, f3, f4, f7, f8, f9, f10; + OI_INT32 y0, y1, y2, y3; + + f0 = (in[0] - in[3]); + f1 = (in[0] + in[3]); + f2 = (in[1] - in[2]); + f3 = (in[1] + in[2]); + + f4 = f1 - f3; + + y0 = -SCALE(f1 + f3, DCT_SHIFT); + y2 = -SCALE(LONG_MULT_DCT(DCTII_4_K06_FIX, f4), DCT_SHIFT); + f7 = f0 + f2; + f8 = LONG_MULT_DCT(DCTII_4_K08_FIX, f0); + f9 = LONG_MULT_DCT(DCTII_4_K09_FIX, f7); + f10 = LONG_MULT_DCT(DCTII_4_K10_FIX, f2); + y3 = -SCALE(f8 + f9, DCT_SHIFT); + y1 = -SCALE(f10 - f9, DCT_SHIFT); + + out[0] = (OI_INT16) - y2; + out[1] = (OI_INT16) - y3; + out[2] = (OI_INT16)0; + out[3] = (OI_INT16)y3; + out[4] = (OI_INT16)y2; + out[5] = (OI_INT16)y1; + out[6] = (OI_INT16)y0; + out[7] = (OI_INT16)y1; +} + +/** +@} +*/ +#endif /* #if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_dct.h b/components/bt/bluedroid/external/sbc/encoder/include/sbc_dct.h new file mode 100644 index 0000000000..165a8c1cd9 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/include/sbc_dct.h @@ -0,0 +1,91 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Definitions for the fast DCT. + * + ******************************************************************************/ + +#ifndef SBC_DCT_H +#define SBC_DCT_H + +#if (SBC_ARM_ASM_OPT==TRUE) +#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1, s32OutLow) \ +{ \ + __asm \ +{ \ + MUL s32OutLow,(SINT32)s16In2, (s32In1>>15) \ +} \ +} +#else +#if (SBC_DSP_OPT==TRUE) +#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow) s32OutLow = SBC_Multiply_32_16_Simplified((SINT32)s16In2,s32In1); +#else +#if (SBC_IPAQ_OPT==TRUE) +/*#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow) s32OutLow=(SINT32)((SINT32)(s16In2)*(SINT32)(s32In1>>15)); */ +#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow) s32OutLow=(SINT32)(((SINT64)s16In2*(SINT64)s32In1)>>15); +#if (SBC_IS_64_MULT_IN_IDCT == TRUE) +#define SBC_MULT_32_32(s32In2, s32In1, s32OutLow) \ +{ \ + s64Temp = ((SINT64) s32In2) * ((SINT64) s32In1)>>31; \ + s32OutLow = (SINT32) s64Temp; \ +} +#endif +#else +#define SBC_MULT_32_16_SIMPLIFIED(s16In2, s32In1 , s32OutLow) \ +{ \ + s32In1Temp = s32In1; \ + s32In2Temp = (SINT32)s16In2; \ + \ + /* Multiply one +ve and the other -ve number */ \ + if (s32In1Temp < 0) \ + { \ + s32In1Temp ^= 0xFFFFFFFF; \ + s32In1Temp++; \ + s32OutLow = (s32In2Temp * (s32In1Temp >> 16)); \ + s32OutLow += (( s32In2Temp * (s32In1Temp & 0xFFFF)) >> 16); \ + s32OutLow ^= 0xFFFFFFFF; \ + s32OutLow++; \ + } \ + else \ + { \ + s32OutLow = (s32In2Temp * (s32In1Temp >> 16)); \ + s32OutLow += (( s32In2Temp * (s32In1Temp & 0xFFFF)) >> 16); \ + } \ + s32OutLow <<= 1; \ +} +#if (SBC_IS_64_MULT_IN_IDCT == TRUE) +#define SBC_MULT_64(s32In1, s32In2, s32OutLow, s32OutHi) \ +{\ + s32OutLow=(SINT32)(((SINT64)s32In1*(SINT64)s32In2)& 0x00000000FFFFFFFF);\ + s32OutHi=(SINT32)(((SINT64)s32In1*(SINT64)s32In2)>>32);\ +} +#define SBC_MULT_32_32(s32In2, s32In1, s32OutLow) \ +{ \ + s32HiTemp = 0; \ + SBC_MULT_64(s32In2,s32In1 , s32OutLow, s32HiTemp); \ + s32OutLow = (((s32OutLow>>15)&0x1FFFF) | (s32HiTemp << 17)); \ +} +#endif + +#endif +#endif +#endif + +#endif diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h b/components/bt/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h new file mode 100644 index 0000000000..cc85b71643 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/include/sbc_enc_func_declare.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Function declarations. + * + ******************************************************************************/ + +#ifndef SBC_FUNCDECLARE_H +#define SBC_FUNCDECLARE_H + +/*#include "sbc_encoder.h"*/ +/* Global data */ +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE) +extern const SINT16 gas32CoeffFor4SBs[]; +extern const SINT16 gas32CoeffFor8SBs[]; +#else +extern const SINT32 gas32CoeffFor4SBs[]; +extern const SINT32 gas32CoeffFor8SBs[]; +#endif + +/* Global functions*/ + +extern void sbc_enc_bit_alloc_mono(SBC_ENC_PARAMS *CodecParams); +extern void sbc_enc_bit_alloc_ste(SBC_ENC_PARAMS *CodecParams); + +extern void SbcAnalysisInit (void); + +extern void SbcAnalysisFilter4(SBC_ENC_PARAMS *strEncParams); +extern void SbcAnalysisFilter8(SBC_ENC_PARAMS *strEncParams); + +extern void SBC_FastIDCT8 (SINT32 *pInVect, SINT32 *pOutVect); +extern void SBC_FastIDCT4 (SINT32 *x0, SINT32 *pOutVect); + +extern void EncPacking(SBC_ENC_PARAMS *strEncParams); +extern void EncQuantizer(SBC_ENC_PARAMS *); +#if (SBC_DSP_OPT==TRUE) +SINT32 SBC_Multiply_32_16_Simplified(SINT32 s32In2Temp, SINT32 s32In1Temp); +#endif +#endif + diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_encoder.h b/components/bt/bluedroid/external/sbc/encoder/include/sbc_encoder.h new file mode 100644 index 0000000000..8e2e6dd364 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/include/sbc_encoder.h @@ -0,0 +1,201 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains constants and structures used by Encoder. + * + ******************************************************************************/ + +#ifndef SBC_ENCODER_H +#define SBC_ENCODER_H + +#define ENCODER_VERSION "0025" + +#ifdef BUILDCFG +#include "bt_target.h" +#endif + +/*DEFINES*/ +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#define SBC_MAX_NUM_OF_SUBBANDS 8 +#define SBC_MAX_NUM_OF_CHANNELS 2 +#define SBC_MAX_NUM_OF_BLOCKS 16 + +#define SBC_LOUDNESS 0 +#define SBC_SNR 1 + +#define SUB_BANDS_8 8 +#define SUB_BANDS_4 4 + +#define SBC_sf16000 0 +#define SBC_sf32000 1 +#define SBC_sf44100 2 +#define SBC_sf48000 3 + +#define SBC_MONO 0 +#define SBC_DUAL 1 +#define SBC_STEREO 2 +#define SBC_JOINT_STEREO 3 + +#define SBC_BLOCK_0 4 +#define SBC_BLOCK_1 8 +#define SBC_BLOCK_2 12 +#define SBC_BLOCK_3 16 + +#define SBC_NULL 0 + +#ifndef SBC_MAX_NUM_FRAME +#define SBC_MAX_NUM_FRAME 1 +#endif + +#ifndef SBC_DSP_OPT +#define SBC_DSP_OPT FALSE +#endif + +/* Set SBC_USE_ARM_PRAGMA to TRUE to use "#pragma arm section zidata" */ +#ifndef SBC_USE_ARM_PRAGMA +#define SBC_USE_ARM_PRAGMA FALSE +#endif + +/* Set SBC_ARM_ASM_OPT to TRUE in case the target is an ARM */ +/* this will replace all the 32 and 64 bit mult by in line assembly code */ +#ifndef SBC_ARM_ASM_OPT +#define SBC_ARM_ASM_OPT FALSE +#endif + +/* green hill compiler option -> Used to distinguish the syntax for inline assembly code*/ +#ifndef SBC_GHS_COMPILER +#define SBC_GHS_COMPILER FALSE +#endif + +/* ARM compiler option -> Used to distinguish the syntax for inline assembly code */ +#ifndef SBC_ARM_COMPILER +#define SBC_ARM_COMPILER TRUE +#endif + +/* Set SBC_IPAQ_OPT to TRUE in case the target is an ARM */ +/* 32 and 64 bit mult will be performed using SINT64 ( usualy __int64 ) cast that usualy give optimal performance if supported */ +#ifndef SBC_IPAQ_OPT +#define SBC_IPAQ_OPT TRUE +#endif + +/* Debug only: set SBC_IS_64_MULT_IN_WINDOW_ACCU to TRUE to use 64 bit multiplication in the windowing */ +/* -> not recomended, more MIPS for the same restitution. */ +#ifndef SBC_IS_64_MULT_IN_WINDOW_ACCU +#define SBC_IS_64_MULT_IN_WINDOW_ACCU FALSE +#endif /*SBC_IS_64_MULT_IN_WINDOW_ACCU */ + +/* Set SBC_IS_64_MULT_IN_IDCT to TRUE to use 64 bits multiplication in the DCT of Matrixing */ +/* -> more MIPS required for a better audio quality. comparasion with the SIG utilities shows a division by 10 of the RMS */ +/* CAUTION: It only apply in the if SBC_FAST_DCT is set to TRUE */ +#ifndef SBC_IS_64_MULT_IN_IDCT +#define SBC_IS_64_MULT_IN_IDCT FALSE +#endif /*SBC_IS_64_MULT_IN_IDCT */ + +/* set SBC_IS_64_MULT_IN_QUANTIZER to TRUE to use 64 bits multiplication in the quantizer */ +/* setting this flag to FALSE add whistling noise at 5.5 and 11 KHz usualy not perceptible by human's hears. */ +#ifndef SBC_IS_64_MULT_IN_QUANTIZER +#define SBC_IS_64_MULT_IN_QUANTIZER TRUE +#endif /*SBC_IS_64_MULT_IN_IDCT */ + +/* Debug only: set this flag to FALSE to disable fast DCT algorithm */ +#ifndef SBC_FAST_DCT +#define SBC_FAST_DCT TRUE +#endif /*SBC_FAST_DCT */ + +/* In case we do not use joint stereo mode the flag save some RAM and ROM in case it is set to FALSE */ +#ifndef SBC_JOINT_STE_INCLUDED +#define SBC_JOINT_STE_INCLUDED TRUE +#endif + +/* TRUE -> application should provide PCM buffer, FALSE PCM buffer reside in SBC_ENC_PARAMS */ +#ifndef SBC_NO_PCM_CPY_OPTION +#define SBC_NO_PCM_CPY_OPTION FALSE +#endif + +#define MINIMUM_ENC_VX_BUFFER_SIZE (8*10*2) +#ifndef ENC_VX_BUFFER_SIZE +#define ENC_VX_BUFFER_SIZE (MINIMUM_ENC_VX_BUFFER_SIZE + 64) +/*#define ENC_VX_BUFFER_SIZE MINIMUM_ENC_VX_BUFFER_SIZE + 1024*/ +#endif + +#ifndef SBC_FOR_EMBEDDED_LINUX +#define SBC_FOR_EMBEDDED_LINUX FALSE +#endif + +/*constants used for index calculation*/ +#define SBC_BLK (SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS) + +#include "sbc_types.h" + +typedef struct SBC_ENC_PARAMS_TAG { + SINT16 s16SamplingFreq; /* 16k, 32k, 44.1k or 48k*/ + SINT16 s16ChannelMode; /* mono, dual, streo or joint streo*/ + SINT16 s16NumOfSubBands; /* 4 or 8 */ + SINT16 s16NumOfChannels; + SINT16 s16NumOfBlocks; /* 4, 8, 12 or 16*/ + SINT16 s16AllocationMethod; /* loudness or SNR*/ + SINT16 s16BitPool; /* 16*numOfSb for mono & dual; + 32*numOfSb for stereo & joint stereo */ + UINT16 u16BitRate; + UINT8 u8NumPacketToEncode; /* number of sbc frame to encode. Default is 1 */ +#if (SBC_JOINT_STE_INCLUDED == TRUE) + SINT16 as16Join[SBC_MAX_NUM_OF_SUBBANDS]; /*1 if JS, 0 otherwise*/ +#endif + + SINT16 s16MaxBitNeed; + SINT16 as16ScaleFactor[SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS]; + + SINT16 *ps16NextPcmBuffer; +#if (SBC_NO_PCM_CPY_OPTION == TRUE) + SINT16 *ps16PcmBuffer; +#else + SINT16 as16PcmBuffer[SBC_MAX_NUM_FRAME * SBC_MAX_NUM_OF_BLOCKS * SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS]; +#endif + + SINT16 s16ScartchMemForBitAlloc[16]; + + SINT32 s32SbBuffer[SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS * SBC_MAX_NUM_OF_BLOCKS]; + + SINT16 as16Bits[SBC_MAX_NUM_OF_CHANNELS * SBC_MAX_NUM_OF_SUBBANDS]; + + UINT8 *pu8Packet; + UINT8 *pu8NextPacket; + UINT16 FrameHeader; + UINT16 u16PacketLength; + +} SBC_ENC_PARAMS; + +#ifdef __cplusplus +extern "C" +{ +#endif +extern void SBC_Encoder(SBC_ENC_PARAMS *strEncParams); +extern void SBC_Encoder_Init(SBC_ENC_PARAMS *strEncParams); +#ifdef __cplusplus +} +#endif +#endif diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_if.h b/components/bt/bluedroid/external/sbc/encoder/include/sbc_if.h new file mode 100644 index 0000000000..993b066340 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/include/sbc_if.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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 _SBC_IF_H +#define _SBC_IF_H + +#define PCM_BUFFER_SIZE 512 + +/* + SBC_Init - called once for each track played + + pcm_sample_freq - 4000 to 48000 + channels - 1 mono 2 stereo + bits_per_sample - 8 or 16 + return - 0 sucess +*/ + +int SBC_init(int pcm_sample_freq, int channels, int bits_per_sample); + +/* + SBC_write - called repeatedly with pcm_in pointer + increasing by length until track is finished. + + pcm_in - pointer to PCM buffer + length - any + sbc_out - pointer to SBC output buffer + return - number of bytes written to sbc_out +*/ + +int SBC_write(unsigned char *pcm_in, int length, unsigned char *sbc_out); + +#endif diff --git a/components/bt/bluedroid/external/sbc/encoder/include/sbc_types.h b/components/bt/bluedroid/external/sbc/encoder/include/sbc_types.h new file mode 100644 index 0000000000..4bb8829c70 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/include/sbc_types.h @@ -0,0 +1,59 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Data type declarations. + * + ******************************************************************************/ + +#ifndef SBC_TYPES_H +#define SBC_TYPES_H + +#include + +#ifdef BUILDCFG +#include "bt_target.h" +#endif + +#include "bt_types.h" + +typedef short SINT16; +typedef long SINT32; + +#if (SBC_IPAQ_OPT == TRUE) + +#if (SBC_FOR_EMBEDDED_LINUX == TRUE) +typedef long long SINT64; +#else +typedef int64_t SINT64; +#endif + +#elif (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) || (SBC_IS_64_MULT_IN_IDCT == TRUE) + +#if (SBC_FOR_EMBEDDED_LINUX == TRUE) +typedef long long SINT64; +#else +typedef int64_t SINT64; +#endif + +#endif + +#define abs32(x) ( (x >= 0) ? x : (-x) ) + +#endif diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c new file mode 100644 index 0000000000..adc0eeda73 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_analysis.c @@ -0,0 +1,1082 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the code that performs Analysis of the input audio + * stream. + * + ******************************************************************************/ +#include "bt_target.h" +#include +#include "sbc_encoder.h" +#include "sbc_enc_func_declare.h" +/*#include */ + +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) +#define WIND_4_SUBBANDS_0_1 (SINT32)0x01659F45 /* gas32CoeffFor4SBs[8] = -gas32CoeffFor4SBs[32] = 0x01659F45 */ +#define WIND_4_SUBBANDS_0_2 (SINT32)0x115B1ED2 /* gas32CoeffFor4SBs[16] = -gas32CoeffFor4SBs[24] = 0x115B1ED2 */ +#define WIND_4_SUBBANDS_1_0 (SINT32)0x001194E6 /* gas32CoeffFor4SBs[1 et 39] = 0x001194E6 */ +#define WIND_4_SUBBANDS_1_1 (SINT32)0x029DBAA3 /* gas32CoeffFor4SBs[9 et 31] = 0x029DBAA3 */ +#define WIND_4_SUBBANDS_1_2 (SINT32)0x18F55C90 /* gas32CoeffFor4SBs[17 et 23] = 0x18F55C90 */ +#define WIND_4_SUBBANDS_1_3 (SINT32)0xF60FAF37 /* gas32CoeffFor4SBs[15 et 25] = 0xF60FAF37 */ +#define WIND_4_SUBBANDS_1_4 (SINT32)0xFF9BB9D5 /* gas32CoeffFor4SBs[7 et 33] = 0xFF9BB9D5 */ +#define WIND_4_SUBBANDS_2_0 (SINT32)0x0030E2D3 /* gas32CoeffFor4SBs[2 et 38] = 0x0030E2D3 */ +#define WIND_4_SUBBANDS_2_1 (SINT32)0x03B23341 /* gas32CoeffFor4SBs[10 et 30] = 0x03B23341 */ +#define WIND_4_SUBBANDS_2_2 (SINT32)0x1F91CA46 /* gas32CoeffFor4SBs[18 et 22] = 0x1F91CA46 */ +#define WIND_4_SUBBANDS_2_3 (SINT32)0xFC4F91D4 /* gas32CoeffFor4SBs[14 et 26] = 0xFC4F91D4 */ +#define WIND_4_SUBBANDS_2_4 (SINT32)0x003D239B /* gas32CoeffFor4SBs[6 et 34] = 0x003D239B */ +#define WIND_4_SUBBANDS_3_0 (SINT32)0x00599403 /* gas32CoeffFor4SBs[3 et 37] = 0x00599403 */ +#define WIND_4_SUBBANDS_3_1 (SINT32)0x041EEE40 /* gas32CoeffFor4SBs[11 et 29] = 0x041EEE40 */ +#define WIND_4_SUBBANDS_3_2 (SINT32)0x2412F251 /* gas32CoeffFor4SBs[19 et 21] = 0x2412F251 */ +#define WIND_4_SUBBANDS_3_3 (SINT32)0x00C8F2BC /* gas32CoeffFor4SBs[13 et 27] = 0x00C8F2BC */ +#define WIND_4_SUBBANDS_3_4 (SINT32)0x007F88E4 /* gas32CoeffFor4SBs[5 et 35] = 0x007F88E4 */ +#define WIND_4_SUBBANDS_4_0 (SINT32)0x007DBCC8 /* gas32CoeffFor4SBs[4 et 36] = 0x007DBCC8 */ +#define WIND_4_SUBBANDS_4_1 (SINT32)0x034FEE2C /* gas32CoeffFor4SBs[12 et 28] = 0x034FEE2C */ +#define WIND_4_SUBBANDS_4_2 (SINT32)0x25AC1FF2 /* gas32CoeffFor4SBs[20] = 0x25AC1FF2 */ + +#define WIND_8_SUBBANDS_0_1 (SINT32)0x00B97348 /* 16 0x00B97348 */ +#define WIND_8_SUBBANDS_0_2 (SINT32)0x08B4307A /* 32 0x08B4307A */ +#define WIND_8_SUBBANDS_1_0 (SINT32)0x00052173 /* 1 et 79 = 0x00052173 */ +#define WIND_8_SUBBANDS_1_1 (SINT32)0x01071B96 /* 17 et 63 = 0x01071B96 */ +#define WIND_8_SUBBANDS_1_2 (SINT32)0x0A9F3E9A /* 33 et 47 = 0x0A9F3E9A*/ +#define WIND_8_SUBBANDS_1_3 (SINT32)0xF9312891 /* 31 et 49 = 0xF9312891 */ +#define WIND_8_SUBBANDS_1_4 (SINT32)0xFF8D6793 /* 15 et 65 = 0xFF8D6793 */ +#define WIND_8_SUBBANDS_2_0 (SINT32)0x000B3F71 /* 2 et 78 = 0x000B3F71 */ +#define WIND_8_SUBBANDS_2_1 (SINT32)0x0156B3CA /* 18 et 62 = 0x0156B3CA */ +#define WIND_8_SUBBANDS_2_2 (SINT32)0x0C7D59B6 /* 34 et 46 = 0x0C7D59B6 */ +#define WIND_8_SUBBANDS_2_3 (SINT32)0xFAFF95FC /* 30 et 50 = 0xFAFF95FC */ +#define WIND_8_SUBBANDS_2_4 (SINT32)0xFFC9F10E /* 14 et 66 = 0xFFC9F10E */ +#define WIND_8_SUBBANDS_3_0 (SINT32)0x00122C7D /* 3 et 77 = 0x00122C7D*/ +#define WIND_8_SUBBANDS_3_1 (SINT32)0x01A1B38B /* 19 et 61 = 0x01A1B38B */ +#define WIND_8_SUBBANDS_3_2 (SINT32)0x0E3BB16F /* 35 et 45 = 0x0E3BB16F */ +#define WIND_8_SUBBANDS_3_3 (SINT32)0xFCA86E7E /* 29 et 51 = 0xFCA86E7E */ +#define WIND_8_SUBBANDS_3_4 (SINT32)0xFFFA2413 /* 13 et 67 = 0xFFFA2413 */ +#define WIND_8_SUBBANDS_4_0 (SINT32)0x001AFF89 /* 4 et 66 = 0x001AFF89 */ +#define WIND_8_SUBBANDS_4_1 (SINT32)0x01E0224C /* 20 et 60 = 0x01E0224C */ +#define WIND_8_SUBBANDS_4_2 (SINT32)0x0FC721F9 /* 36 et 44 = 0x0FC721F9 */ +#define WIND_8_SUBBANDS_4_3 (SINT32)0xFE20435D /* 28 et 52 = 0xFE20435D */ +#define WIND_8_SUBBANDS_4_4 (SINT32)0x001D8FD2 /* 12 et 68 = 0x001D8FD2 */ +#define WIND_8_SUBBANDS_5_0 (SINT32)0x00255A62 /* 5 et 75 = 0x00255A62 */ +#define WIND_8_SUBBANDS_5_1 (SINT32)0x0209291F /* 21 et 59 = 0x0209291F */ +#define WIND_8_SUBBANDS_5_2 (SINT32)0x110ECEF0 /* 37 et 43 = 0x110ECEF0 */ +#define WIND_8_SUBBANDS_5_3 (SINT32)0xFF5EEB73 /* 27 et 53 = 0xFF5EEB73 */ +#define WIND_8_SUBBANDS_5_4 (SINT32)0x0034F8B6 /* 11 et 69 = 0x0034F8B6 */ +#define WIND_8_SUBBANDS_6_0 (SINT32)0x003060F4 /* 6 et 74 = 0x003060F4 */ +#define WIND_8_SUBBANDS_6_1 (SINT32)0x02138653 /* 22 et 58 = 0x02138653 */ +#define WIND_8_SUBBANDS_6_2 (SINT32)0x120435FA /* 38 et 42 = 0x120435FA */ +#define WIND_8_SUBBANDS_6_3 (SINT32)0x005FD0FF /* 26 et 54 = 0x005FD0FF */ +#define WIND_8_SUBBANDS_6_4 (SINT32)0x00415B75 /* 10 et 70 = 0x00415B75 */ +#define WIND_8_SUBBANDS_7_0 (SINT32)0x003A72E7 /* 7 et 73 = 0x003A72E7 */ +#define WIND_8_SUBBANDS_7_1 (SINT32)0x01F5F424 /* 23 et 57 = 0x01F5F424 */ +#define WIND_8_SUBBANDS_7_2 (SINT32)0x129C226F /* 39 et 41 = 0x129C226F */ +#define WIND_8_SUBBANDS_7_3 (SINT32)0x01223EBA /* 25 et 55 = 0x01223EBA */ +#define WIND_8_SUBBANDS_7_4 (SINT32)0x0044EF48 /* 9 et 71 = 0x0044EF48 */ +#define WIND_8_SUBBANDS_8_0 (SINT32)0x0041EC6A /* 8 et 72 = 0x0041EC6A */ +#define WIND_8_SUBBANDS_8_1 (SINT32)0x01A7ECEF /* 24 et 56 = 0x01A7ECEF */ +#define WIND_8_SUBBANDS_8_2 (SINT32)0x12CF6C75 /* 40 = 0x12CF6C75 */ +#else +#define WIND_4_SUBBANDS_0_1 (SINT16)0x0166 /* gas32CoeffFor4SBs[8] = -gas32CoeffFor4SBs[32] = 0x01659F45 */ +#define WIND_4_SUBBANDS_0_2 (SINT16)0x115B /* gas32CoeffFor4SBs[16] = -gas32CoeffFor4SBs[24] = 0x115B1ED2 */ +#define WIND_4_SUBBANDS_1_0 (SINT16)0x0012 /* gas32CoeffFor4SBs[1 et 39] = 0x001194E6 */ +#define WIND_4_SUBBANDS_1_1 (SINT16)0x029E /* gas32CoeffFor4SBs[9 et 31] = 0x029DBAA3 */ +#define WIND_4_SUBBANDS_1_2 (SINT16)0x18F5 /* gas32CoeffFor4SBs[17 et 23] = 0x18F55C90 */ +#define WIND_4_SUBBANDS_1_3 (SINT16)0xF610 /* gas32CoeffFor4SBs[15 et 25] = 0xF60FAF37 */ +#define WIND_4_SUBBANDS_1_4 (SINT16)0xFF9C /* gas32CoeffFor4SBs[7 et 33] = 0xFF9BB9D5 */ +#define WIND_4_SUBBANDS_2_0 (SINT16)0x0031 /* gas32CoeffFor4SBs[2 et 38] = 0x0030E2D3 */ +#define WIND_4_SUBBANDS_2_1 (SINT16)0x03B2 /* gas32CoeffFor4SBs[10 et 30] = 0x03B23341 */ +#define WIND_4_SUBBANDS_2_2 (SINT16)0x1F91 /* gas32CoeffFor4SBs[18 et 22] = 0x1F91CA46 */ +#define WIND_4_SUBBANDS_2_3 (SINT16)0xFC50 /* gas32CoeffFor4SBs[14 et 26] = 0xFC4F91D4 */ +#define WIND_4_SUBBANDS_2_4 (SINT16)0x003D /* gas32CoeffFor4SBs[6 et 34] = 0x003D239B */ +#define WIND_4_SUBBANDS_3_0 (SINT16)0x005A /* gas32CoeffFor4SBs[3 et 37] = 0x00599403 */ +#define WIND_4_SUBBANDS_3_1 (SINT16)0x041F /* gas32CoeffFor4SBs[11 et 29] = 0x041EEE40 */ +#define WIND_4_SUBBANDS_3_2 (SINT16)0x2413 /* gas32CoeffFor4SBs[19 et 21] = 0x2412F251 */ +#define WIND_4_SUBBANDS_3_3 (SINT16)0x00C9 /* gas32CoeffFor4SBs[13 et 27] = 0x00C8F2BC */ +#define WIND_4_SUBBANDS_3_4 (SINT16)0x0080 /* gas32CoeffFor4SBs[5 et 35] = 0x007F88E4 */ +#define WIND_4_SUBBANDS_4_0 (SINT16)0x007E /* gas32CoeffFor4SBs[4 et 36] = 0x007DBCC8 */ +#define WIND_4_SUBBANDS_4_1 (SINT16)0x0350 /* gas32CoeffFor4SBs[12 et 28] = 0x034FEE2C */ +#define WIND_4_SUBBANDS_4_2 (SINT16)0x25AC /* gas32CoeffFor4SBs[20] = 25AC1FF2 */ + +#define WIND_8_SUBBANDS_0_1 (SINT16)0x00B9 /* 16 0x12CF6C75 */ +#define WIND_8_SUBBANDS_0_2 (SINT16)0x08B4 /* 32 0x08B4307A */ +#define WIND_8_SUBBANDS_1_0 (SINT16)0x0005 /* 1 et 79 = 0x00052173 */ +#define WIND_8_SUBBANDS_1_1 (SINT16)0x0107 /* 17 et 63 = 0x01071B96 */ +#define WIND_8_SUBBANDS_1_2 (SINT16)0x0A9F /* 33 et 47 = 0x0A9F3E9A*/ +#define WIND_8_SUBBANDS_1_3 (SINT16)0xF931 /* 31 et 49 = 0xF9312891 */ +#define WIND_8_SUBBANDS_1_4 (SINT16)0xFF8D /* 15 et 65 = 0xFF8D6793 */ +#define WIND_8_SUBBANDS_2_0 (SINT16)0x000B /* 2 et 78 = 0x000B3F71 */ +#define WIND_8_SUBBANDS_2_1 (SINT16)0x0157 /* 18 et 62 = 0x0156B3CA */ +#define WIND_8_SUBBANDS_2_2 (SINT16)0x0C7D /* 34 et 46 = 0x0C7D59B6 */ +#define WIND_8_SUBBANDS_2_3 (SINT16)0xFB00 /* 30 et 50 = 0xFAFF95FC */ +#define WIND_8_SUBBANDS_2_4 (SINT16)0xFFCA /* 14 et 66 = 0xFFC9F10E */ +#define WIND_8_SUBBANDS_3_0 (SINT16)0x0012 /* 3 et 77 = 0x00122C7D*/ +#define WIND_8_SUBBANDS_3_1 (SINT16)0x01A2 /* 19 et 61 = 0x01A1B38B */ +#define WIND_8_SUBBANDS_3_2 (SINT16)0x0E3C /* 35 et 45 = 0x0E3BB16F */ +#define WIND_8_SUBBANDS_3_3 (SINT16)0xFCA8 /* 29 et 51 = 0xFCA86E7E */ +#define WIND_8_SUBBANDS_3_4 (SINT16)0xFFFA /* 13 et 67 = 0xFFFA2413 */ +#define WIND_8_SUBBANDS_4_0 (SINT16)0x001B /* 4 et 66 = 0x001AFF89 */ +#define WIND_8_SUBBANDS_4_1 (SINT16)0x01E0 /* 20 et 60 = 0x01E0224C */ +#define WIND_8_SUBBANDS_4_2 (SINT16)0x0FC7 /* 36 et 44 = 0x0FC721F9 */ +#define WIND_8_SUBBANDS_4_3 (SINT16)0xFE20 /* 28 et 52 = 0xFE20435D */ +#define WIND_8_SUBBANDS_4_4 (SINT16)0x001E /* 12 et 68 = 0x001D8FD2 */ +#define WIND_8_SUBBANDS_5_0 (SINT16)0x0025 /* 5 et 75 = 0x00255A62 */ +#define WIND_8_SUBBANDS_5_1 (SINT16)0x0209 /* 21 et 59 = 0x0209291F */ +#define WIND_8_SUBBANDS_5_2 (SINT16)0x110F /* 37 et 43 = 0x110ECEF0 */ +#define WIND_8_SUBBANDS_5_3 (SINT16)0xFF5F /* 27 et 53 = 0xFF5EEB73 */ +#define WIND_8_SUBBANDS_5_4 (SINT16)0x0035 /* 11 et 69 = 0x0034F8B6 */ +#define WIND_8_SUBBANDS_6_0 (SINT16)0x0030 /* 6 et 74 = 0x003060F4 */ +#define WIND_8_SUBBANDS_6_1 (SINT16)0x0214 /* 22 et 58 = 0x02138653 */ +#define WIND_8_SUBBANDS_6_2 (SINT16)0x1204 /* 38 et 42 = 0x120435FA */ +#define WIND_8_SUBBANDS_6_3 (SINT16)0x0060 /* 26 et 54 = 0x005FD0FF */ +#define WIND_8_SUBBANDS_6_4 (SINT16)0x0041 /* 10 et 70 = 0x00415B75 */ +#define WIND_8_SUBBANDS_7_0 (SINT16)0x003A /* 7 et 73 = 0x003A72E7 */ +#define WIND_8_SUBBANDS_7_1 (SINT16)0x01F6 /* 23 et 57 = 0x01F5F424 */ +#define WIND_8_SUBBANDS_7_2 (SINT16)0x129C /* 39 et 41 = 0x129C226F */ +#define WIND_8_SUBBANDS_7_3 (SINT16)0x0122 /* 25 et 55 = 0x01223EBA */ +#define WIND_8_SUBBANDS_7_4 (SINT16)0x0045 /* 9 et 71 = 0x0044EF48 */ +#define WIND_8_SUBBANDS_8_0 (SINT16)0x0042 /* 8 et 72 = 0x0041EC6A */ +#define WIND_8_SUBBANDS_8_1 (SINT16)0x01A8 /* 24 et 56 = 0x01A7ECEF */ +#define WIND_8_SUBBANDS_8_2 (SINT16)0x12CF /* 40 = 0x12CF6C75 */ +#endif + +#if (SBC_USE_ARM_PRAGMA==TRUE) +#pragma arm section zidata = "sbc_s32_analysis_section" +#endif +static SINT32 s32DCTY[16] = {0}; +static SINT32 s32X[ENC_VX_BUFFER_SIZE / 2]; +static SINT16 *s16X = (SINT16 *) s32X; /* s16X must be 32 bits aligned cf SHIFTUP_X8_2*/ +#if (SBC_USE_ARM_PRAGMA==TRUE) +#pragma arm section zidata +#endif + +/* This macro is for 4 subbands */ +#define SHIFTUP_X4 \ +{ \ + ps32X=(SINT32 *)(s16X+EncMaxShiftCounter+38); \ + for (i=0;i<9;i++) \ + { \ + *ps32X=*(ps32X-2-(ShiftCounter>>1)); ps32X--; \ + *ps32X=*(ps32X-2-(ShiftCounter>>1)); ps32X--; \ + } \ +} +#define SHIFTUP_X4_2 \ +{ \ + ps32X=(SINT32 *)(s16X+EncMaxShiftCounter+38); \ + ps32X2=(SINT32 *)(s16X+(EncMaxShiftCounter<<1)+78); \ + for (i=0;i<9;i++) \ + { \ + *ps32X=*(ps32X-2-(ShiftCounter>>1)); *(ps32X2)=*(ps32X2-2-(ShiftCounter>>1)); ps32X--; ps32X2--; \ + *ps32X=*(ps32X-2-(ShiftCounter>>1)); *(ps32X2)=*(ps32X2-2-(ShiftCounter>>1)); ps32X--; ps32X2--; \ + } \ +} + +/* This macro is for 8 subbands */ +#define SHIFTUP_X8 \ +{ \ + ps32X=(SINT32 *)(s16X+EncMaxShiftCounter+78); \ + for (i=0;i<9;i++) \ + { \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); ps32X--; \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); ps32X--; \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); ps32X--; \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); ps32X--; \ + } \ +} +#define SHIFTUP_X8_2 \ +{ \ + ps32X=(SINT32 *)(s16X+EncMaxShiftCounter+78); \ + ps32X2=(SINT32 *)(s16X+(EncMaxShiftCounter<<1)+158); \ + for (i=0;i<9;i++) \ + { \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--; ps32X2--; \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--; ps32X2--; \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--; ps32X2--; \ + *ps32X=*(ps32X-4-(ShiftCounter>>1)); *(ps32X2)=*(ps32X2-4-(ShiftCounter>>1)); ps32X--; ps32X2--; \ + } \ +} + +#if (SBC_ARM_ASM_OPT==TRUE) +#define WINDOW_ACCU_8_0 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_0_1,(s16X[ChOffset+16]-s16X[ChOffset+64]);\ + MLA s32Hi,WIND_8_SUBBANDS_0_2,(s16X[ChOffset+32]-s16X[ChOffset+48]),s32Hi;\ + MOV s32DCTY[0],s32Hi;\ + }\ +} +#define WINDOW_ACCU_8_1_15 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_1_0,s16X[ChOffset+1];\ + MUL s32Hi2,WIND_8_SUBBANDS_1_0,s16X[ChOffset+64+15];\ + MLA s32Hi,WIND_8_SUBBANDS_1_1,s16X[ChOffset+16+1],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_1_1,s16X[ChOffset+48+15],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_1_2,s16X[ChOffset+32+1],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_1_2,s16X[ChOffset+32+15],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_1_3,s16X[ChOffset+48+1],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_1_3,s16X[ChOffset+16+15],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_1_4,s16X[ChOffset+64+1],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_1_4,s16X[ChOffset+15],s32Hi2;\ + MOV s32DCTY[1],s32Hi;\ + MOV s32DCTY[15],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_8_2_14 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_2_0,s16X[ChOffset+2];\ + MUL s32Hi2,WIND_8_SUBBANDS_2_0,s16X[ChOffset+64+14];\ + MLA s32Hi,WIND_8_SUBBANDS_2_1,s16X[ChOffset+16+2],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_2_1,s16X[ChOffset+48+14],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_2_2,s16X[ChOffset+32+2],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_2_2,s16X[ChOffset+32+14],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_2_3,s16X[ChOffset+48+2],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_2_3,s16X[ChOffset+16+14],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_2_4,s16X[ChOffset+64+2],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_2_4,s16X[ChOffset+14],s32Hi2;\ + MOV s32DCTY[2],s32Hi;\ + MOV s32DCTY[14],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_8_3_13 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_3_0,s16X[ChOffset+3];\ + MUL s32Hi2,WIND_8_SUBBANDS_3_0,s16X[ChOffset+64+13];\ + MLA s32Hi,WIND_8_SUBBANDS_3_1,s16X[ChOffset+16+3],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_3_1,s16X[ChOffset+48+13],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_3_2,s16X[ChOffset+32+3],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_3_2,s16X[ChOffset+32+13],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_3_3,s16X[ChOffset+48+3],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_3_3,s16X[ChOffset+16+13],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_3_4,s16X[ChOffset+64+3],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_3_4,s16X[ChOffset+13],s32Hi2;\ + MOV s32DCTY[3],s32Hi;\ + MOV s32DCTY[13],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_8_4_12 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_4_0,s16X[ChOffset+4];\ + MUL s32Hi2,WIND_8_SUBBANDS_4_0,s16X[ChOffset+64+12];\ + MLA s32Hi,WIND_8_SUBBANDS_4_1,s16X[ChOffset+16+4],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_4_1,s16X[ChOffset+48+12],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_4_2,s16X[ChOffset+32+4],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_4_2,s16X[ChOffset+32+12],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_4_3,s16X[ChOffset+48+4],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_4_3,s16X[ChOffset+16+12],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_4_4,s16X[ChOffset+64+4],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_4_4,s16X[ChOffset+12],s32Hi2;\ + MOV s32DCTY[4],s32Hi;\ + MOV s32DCTY[12],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_8_5_11 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_5_0,s16X[ChOffset+5];\ + MUL s32Hi2,WIND_8_SUBBANDS_5_0,s16X[ChOffset+64+11];\ + MLA s32Hi,WIND_8_SUBBANDS_5_1,s16X[ChOffset+16+5],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_5_1,s16X[ChOffset+48+11],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_5_2,s16X[ChOffset+32+5],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_5_2,s16X[ChOffset+32+11],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_5_3,s16X[ChOffset+48+5],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_5_3,s16X[ChOffset+16+11],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_5_4,s16X[ChOffset+64+5],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_5_4,s16X[ChOffset+11],s32Hi2;\ + MOV s32DCTY[5],s32Hi;\ + MOV s32DCTY[11],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_8_6_10 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_6_0,s16X[ChOffset+6];\ + MUL s32Hi2,WIND_8_SUBBANDS_6_0,s16X[ChOffset+64+10];\ + MLA s32Hi,WIND_8_SUBBANDS_6_1,s16X[ChOffset+16+6],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_6_1,s16X[ChOffset+48+10],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_6_2,s16X[ChOffset+32+6],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_6_2,s16X[ChOffset+32+10],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_6_3,s16X[ChOffset+48+6],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_6_3,s16X[ChOffset+16+10],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_6_4,s16X[ChOffset+64+6],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_6_4,s16X[ChOffset+10],s32Hi2;\ + MOV s32DCTY[6],s32Hi;\ + MOV s32DCTY[10],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_8_7_9 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_7_0,s16X[ChOffset+7];\ + MUL s32Hi2,WIND_8_SUBBANDS_7_0,s16X[ChOffset+64+9];\ + MLA s32Hi,WIND_8_SUBBANDS_7_1,s16X[ChOffset+16+7],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_7_1,s16X[ChOffset+48+9],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_7_2,s16X[ChOffset+32+7],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_7_2,s16X[ChOffset+32+9],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_7_3,s16X[ChOffset+48+7],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_7_3,s16X[ChOffset+16+9],s32Hi2;\ + MLA s32Hi,WIND_8_SUBBANDS_7_4,s16X[ChOffset+64+7],s32Hi;\ + MLA s32Hi2,WIND_8_SUBBANDS_7_4,s16X[ChOffset+9],s32Hi2;\ + MOV s32DCTY[7],s32Hi;\ + MOV s32DCTY[9],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_8_8 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_8_SUBBANDS_8_0,(s16X[ChOffset+8]+s16X[ChOffset+8+64]);\ + MLA s32Hi,WIND_8_SUBBANDS_8_1,(s16X[ChOffset+8+16]+s16X[ChOffset+8+64]),s32Hi;\ + MLA s32Hi,WIND_8_SUBBANDS_8_2,s16X[ChOffset+8+32],s32Hi;\ + MOV s32DCTY[8],s32Hi;\ + }\ +} +#define WINDOW_ACCU_4_0 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_4_SUBBANDS_0_1,(s16X[ChOffset+8]-s16X[ChOffset+32]);\ + MLA s32Hi,WIND_4_SUBBANDS_0_2,(s16X[ChOffset+16]-s16X[ChOffset+24]),s32Hi;\ + MOV s32DCTY[0],s32Hi;\ + }\ +} +#define WINDOW_ACCU_4_1_7 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_4_SUBBANDS_1_0,s16X[ChOffset+1];\ + MUL s32Hi2,WIND_4_SUBBANDS_1_0,s16X[ChOffset+32+7];\ + MLA s32Hi,WIND_4_SUBBANDS_1_1,s16X[ChOffset+8+1],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_1_1,s16X[ChOffset+24+7],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_1_2,s16X[ChOffset+16+1],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_1_2,s16X[ChOffset+16+7],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_1_3,s16X[ChOffset+24+1],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_1_3,s16X[ChOffset+8+7],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_1_4,s16X[ChOffset+32+1],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_1_4,s16X[ChOffset+7],s32Hi2;\ + MOV s32DCTY[1],s32Hi;\ + MOV s32DCTY[7],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_4_2_6 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_4_SUBBANDS_2_0,s16X[ChOffset+2];\ + MUL s32Hi2,WIND_4_SUBBANDS_2_0,s16X[ChOffset+32+6];\ + MLA s32Hi,WIND_4_SUBBANDS_2_1,s16X[ChOffset+8+2],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_2_1,s16X[ChOffset+24+6],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_2_2,s16X[ChOffset+16+2],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_2_2,s16X[ChOffset+16+6],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_2_3,s16X[ChOffset+24+2],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_2_3,s16X[ChOffset+8+6],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_2_4,s16X[ChOffset+32+2],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_2_4,s16X[ChOffset+6],s32Hi2;\ + MOV s32DCTY[2],s32Hi;\ + MOV s32DCTY[6],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_4_3_5 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_4_SUBBANDS_3_0,s16X[ChOffset+3];\ + MUL s32Hi2,WIND_4_SUBBANDS_3_0,s16X[ChOffset+32+5];\ + MLA s32Hi,WIND_4_SUBBANDS_3_1,s16X[ChOffset+8+3],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_3_1,s16X[ChOffset+24+5],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_3_2,s16X[ChOffset+16+3],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_3_2,s16X[ChOffset+16+5],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_3_3,s16X[ChOffset+24+3],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_3_3,s16X[ChOffset+8+5],s32Hi2;\ + MLA s32Hi,WIND_4_SUBBANDS_3_4,s16X[ChOffset+32+3],s32Hi;\ + MLA s32Hi2,WIND_4_SUBBANDS_3_4,s16X[ChOffset+5],s32Hi2;\ + MOV s32DCTY[3],s32Hi;\ + MOV s32DCTY[5],s32Hi2;\ + }\ +} +#define WINDOW_ACCU_4_4 \ +{\ + __asm\ + {\ + MUL s32Hi,WIND_4_SUBBANDS_4_0,(s16X[ChOffset+4]+s16X[ChOffset+4+32]);\ + MLA s32Hi,WIND_4_SUBBANDS_4_1,(s16X[ChOffset+4+8]+s16X[ChOffset+4+24]),s32Hi;\ + MLA s32Hi,WIND_4_SUBBANDS_4_2,s16X[ChOffset+4+16],s32Hi;\ + MOV s32DCTY[4],s32Hi;\ + }\ +} + +#define WINDOW_PARTIAL_4 \ +{\ + WINDOW_ACCU_4_0; WINDOW_ACCU_4_1_7;\ + WINDOW_ACCU_4_2_6; WINDOW_ACCU_4_3_5;\ + WINDOW_ACCU_4_4;\ +} + +#define WINDOW_PARTIAL_8 \ +{\ + WINDOW_ACCU_8_0; WINDOW_ACCU_8_1_15;\ + WINDOW_ACCU_8_2_14; WINDOW_ACCU_8_3_13;\ + WINDOW_ACCU_8_4_12; WINDOW_ACCU_8_5_11;\ + WINDOW_ACCU_8_6_10; WINDOW_ACCU_8_7_9;\ + WINDOW_ACCU_8_8;\ +} + +#else +#if (SBC_IPAQ_OPT==TRUE) + +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) +#define WINDOW_ACCU_8_0 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_0_1*(SINT64)(s16X[ChOffset+16]-s16X[ChOffset+64]);\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_0_2*(SINT64)(s16X[ChOffset+32]-s16X[ChOffset+48]);\ + s32DCTY[0]=(SINT32)(s64Temp>>16);\ +} +#define WINDOW_ACCU_8_1_15 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_1_0*(SINT64)s16X[ChOffset+1];\ + s64Temp2=(SINT64)WIND_8_SUBBANDS_1_0*(SINT64)s16X[ChOffset+64+15];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_1_1*(SINT64)s16X[ChOffset+16+1];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_1_1*(SINT64)s16X[ChOffset+48+15];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_1_2*(SINT64)s16X[ChOffset+32+1];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_1_2*(SINT64)s16X[ChOffset+32+15];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_1_3*(SINT64)s16X[ChOffset+48+1];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_1_3*(SINT64)s16X[ChOffset+16+15];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_1_4*(SINT64)s16X[ChOffset+64+1];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_1_4*(SINT64)s16X[ChOffset+15];\ + s32DCTY[1]=(SINT32)(s64Temp>>16);\ + s32DCTY[15]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_8_2_14 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_2_0*(SINT64)s16X[ChOffset+2];\ + s64Temp2=(SINT64)WIND_8_SUBBANDS_2_0*(SINT64)s16X[ChOffset+64+14];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_2_1*(SINT64)s16X[ChOffset+16+2];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_2_1*(SINT64)s16X[ChOffset+48+14];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_2_2*(SINT64)s16X[ChOffset+32+2];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_2_2*(SINT64)s16X[ChOffset+32+14];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_2_3*(SINT64)s16X[ChOffset+48+2];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_2_3*(SINT64)s16X[ChOffset+16+14];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_2_4*(SINT64)s16X[ChOffset+64+2];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_2_4*(SINT64)s16X[ChOffset+14];\ + s32DCTY[2]=(SINT32)(s64Temp>>16);\ + s32DCTY[14]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_8_3_13 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_3_0*(SINT64)s16X[ChOffset+3];\ + s64Temp2=(SINT64)WIND_8_SUBBANDS_3_0*(SINT64)s16X[ChOffset+64+13];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_3_1*(SINT64)s16X[ChOffset+16+3];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_3_1*(SINT64)s16X[ChOffset+48+13];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_3_2*(SINT64)s16X[ChOffset+32+3];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_3_2*(SINT64)s16X[ChOffset+32+13];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_3_3*(SINT64)s16X[ChOffset+48+3];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_3_3*(SINT64)s16X[ChOffset+16+13];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_3_4*(SINT64)s16X[ChOffset+64+3];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_3_4*(SINT64)s16X[ChOffset+13];\ + s32DCTY[3]=(SINT32)(s64Temp>>16);\ + s32DCTY[13]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_8_4_12 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_4_0*(SINT64)s16X[ChOffset+4];\ + s64Temp2=(SINT64)WIND_8_SUBBANDS_4_0*(SINT64)s16X[ChOffset+64+12];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_4_1*(SINT64)s16X[ChOffset+16+4];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_4_1*(SINT64)s16X[ChOffset+48+12];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_4_2*(SINT64)s16X[ChOffset+32+4];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_4_2*(SINT64)s16X[ChOffset+32+12];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_4_3*(SINT64)s16X[ChOffset+48+4];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_4_3*(SINT64)s16X[ChOffset+16+12];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_4_4*(SINT64)s16X[ChOffset+64+4];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_4_4*(SINT64)s16X[ChOffset+12];\ + s32DCTY[4]=(SINT32)(s64Temp>>16);\ + s32DCTY[12]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_8_5_11 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_5_0*(SINT64)s16X[ChOffset+5];\ + s64Temp2=(SINT64)WIND_8_SUBBANDS_5_0*(SINT64)s16X[ChOffset+64+11];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_5_1*(SINT64)s16X[ChOffset+16+5];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_5_1*(SINT64)s16X[ChOffset+48+11];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_5_2*(SINT64)s16X[ChOffset+32+5];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_5_2*(SINT64)s16X[ChOffset+32+11];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_5_3*(SINT64)s16X[ChOffset+48+5];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_5_3*(SINT64)s16X[ChOffset+16+11];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_5_4*(SINT64)s16X[ChOffset+64+5];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_5_4*(SINT64)s16X[ChOffset+11];\ + s32DCTY[5]=(SINT32)(s64Temp>>16);\ + s32DCTY[11]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_8_6_10 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_6_0*(SINT64)s16X[ChOffset+6];\ + s64Temp2=(SINT64)WIND_8_SUBBANDS_6_0*(SINT64)s16X[ChOffset+64+10];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_6_1*(SINT64)s16X[ChOffset+16+6];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_6_1*(SINT64)s16X[ChOffset+48+10];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_6_2*(SINT64)s16X[ChOffset+32+6];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_6_2*(SINT64)s16X[ChOffset+32+10];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_6_3*(SINT64)s16X[ChOffset+48+6];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_6_3*(SINT64)s16X[ChOffset+16+10];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_6_4*(SINT64)s16X[ChOffset+64+6];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_6_4*(SINT64)s16X[ChOffset+10];\ + s32DCTY[6]=(SINT32)(s64Temp>>16);\ + s32DCTY[10]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_8_7_9 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_7_0*(SINT64)s16X[ChOffset+7];\ + s64Temp2=(SINT64)WIND_8_SUBBANDS_7_0*(SINT64)s16X[ChOffset+64+9];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_7_1*(SINT64)s16X[ChOffset+16+7];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_7_1*(SINT64)s16X[ChOffset+48+9];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_7_2*(SINT64)s16X[ChOffset+32+7];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_7_2*(SINT64)s16X[ChOffset+32+9];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_7_3*(SINT64)s16X[ChOffset+48+7];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_7_3*(SINT64)s16X[ChOffset+16+9];\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_7_4*(SINT64)s16X[ChOffset+64+7];\ + s64Temp2+=(SINT64)WIND_8_SUBBANDS_7_4*(SINT64)s16X[ChOffset+9];\ + s32DCTY[7]=(SINT32)(s64Temp>>16);\ + s32DCTY[9]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_8_8 \ +{\ + s64Temp=(SINT64)WIND_8_SUBBANDS_8_0*(SINT64)(s16X[ChOffset+8]+s16X[ChOffset+64+8]);\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_8_1*(SINT64)(s16X[ChOffset+16+8]+s16X[ChOffset+48+8]);\ + s64Temp+=(SINT64)WIND_8_SUBBANDS_8_2*(SINT64)s16X[ChOffset+32+8];\ + s32DCTY[8]=(SINT32)(s64Temp>>16);\ +} +#define WINDOW_ACCU_4_0 \ +{\ + s64Temp=(SINT64)WIND_4_SUBBANDS_0_1*(SINT64)(s16X[ChOffset+8]-s16X[ChOffset+32]);\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_0_2*(SINT64)(s16X[ChOffset+16]-s16X[ChOffset+24]);\ + s32DCTY[0]=(SINT32)(s64Temp>>16);\ +} +#define WINDOW_ACCU_4_1_7 \ +{\ + s64Temp=(SINT64)WIND_4_SUBBANDS_1_0*(SINT64)s16X[ChOffset+1];\ + s64Temp2=(SINT64)WIND_4_SUBBANDS_1_0*(SINT64)s16X[ChOffset+32+7];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_1_1*(SINT64)s16X[ChOffset+8+1];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_1_1*(SINT64)s16X[ChOffset+24+7];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_1_2*(SINT64)s16X[ChOffset+16+1];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_1_2*(SINT64)s16X[ChOffset+16+7];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_1_3*(SINT64)s16X[ChOffset+24+1];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_1_3*(SINT64)s16X[ChOffset+8+7];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_1_4*(SINT64)s16X[ChOffset+32+1];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_1_4*(SINT64)s16X[ChOffset+7];\ + s32DCTY[1]=(SINT32)(s64Temp>>16);\ + s32DCTY[7]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_4_2_6 \ +{\ + s64Temp=(SINT64)WIND_4_SUBBANDS_2_0*(SINT64)s16X[ChOffset+2];\ + s64Temp2=(SINT64)WIND_4_SUBBANDS_2_0*(SINT64)s16X[ChOffset+32+6];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_2_1*(SINT64)s16X[ChOffset+8+2];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_2_1*(SINT64)s16X[ChOffset+24+6];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_2_2*(SINT64)s16X[ChOffset+16+2];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_2_2*(SINT64)s16X[ChOffset+16+6];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_2_3*(SINT64)s16X[ChOffset+24+2];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_2_3*(SINT64)s16X[ChOffset+8+6];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_2_4*(SINT64)s16X[ChOffset+32+2];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_2_4*(SINT64)s16X[ChOffset+6];\ + s32DCTY[2]=(SINT32)(s64Temp>>16);\ + s32DCTY[6]=(SINT32)(s64Temp2>>16);\ +} +#define WINDOW_ACCU_4_3_5 \ +{\ + s64Temp=(SINT64)WIND_4_SUBBANDS_3_0*(SINT64)s16X[ChOffset+3];\ + s64Temp2=(SINT64)WIND_4_SUBBANDS_3_0*(SINT64)s16X[ChOffset+32+5];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_3_1*(SINT64)s16X[ChOffset+8+3];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_3_1*(SINT64)s16X[ChOffset+24+5];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_3_2*(SINT64)s16X[ChOffset+16+3];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_3_2*(SINT64)s16X[ChOffset+16+5];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_3_3*(SINT64)s16X[ChOffset+24+3];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_3_3*(SINT64)s16X[ChOffset+8+5];\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_3_4*(SINT64)s16X[ChOffset+32+3];\ + s64Temp2+=(SINT64)WIND_4_SUBBANDS_3_4*(SINT64)s16X[ChOffset+5];\ + s32DCTY[3]=(SINT32)(s64Temp>>16);\ + s32DCTY[5]=(SINT32)(s64Temp2>>16);\ +} + +#define WINDOW_ACCU_4_4 \ +{\ + s64Temp=(SINT64)WIND_4_SUBBANDS_4_0*(SINT64)(s16X[ChOffset+4]+s16X[ChOffset+4+32]);\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_4_1*(SINT64)(s16X[ChOffset+4+8]+s16X[ChOffset+4+24]);\ + s64Temp+=(SINT64)WIND_4_SUBBANDS_4_2*(SINT64)s16X[ChOffset+4+16];\ + s32DCTY[4]=(SINT32)(s64Temp>>16);\ +} +#else /* SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE */ +#define WINDOW_ACCU_8_0 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_0_1*(SINT32)(s16X[ChOffset+16]-s16X[ChOffset+64]);\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_0_2*(SINT32)(s16X[ChOffset+32]-s16X[ChOffset+48]);\ + s32DCTY[0]=(SINT32)s32Temp;\ +} +#define WINDOW_ACCU_8_1_15 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_1_0*(SINT32)s16X[ChOffset+1];\ + s32Temp2=(SINT32)WIND_8_SUBBANDS_1_0*(SINT32)s16X[ChOffset+64+15];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_1_1*(SINT32)s16X[ChOffset+16+1];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_1_1*(SINT32)s16X[ChOffset+48+15];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_1_2*(SINT32)s16X[ChOffset+32+1];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_1_2*(SINT32)s16X[ChOffset+32+15];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_1_3*(SINT32)s16X[ChOffset+48+1];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_1_3*(SINT32)s16X[ChOffset+16+15];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_1_4*(SINT32)s16X[ChOffset+64+1];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_1_4*(SINT32)s16X[ChOffset+15];\ + s32DCTY[1]=(SINT32)s32Temp;\ + s32DCTY[15]=(SINT32)s32Temp2;\ +} +#define WINDOW_ACCU_8_2_14 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_2_0*(SINT32)s16X[ChOffset+2];\ + s32Temp2=(SINT32)WIND_8_SUBBANDS_2_0*(SINT32)s16X[ChOffset+64+14];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_2_1*(SINT32)s16X[ChOffset+16+2];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_2_1*(SINT32)s16X[ChOffset+48+14];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_2_2*(SINT32)s16X[ChOffset+32+2];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_2_2*(SINT32)s16X[ChOffset+32+14];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_2_3*(SINT32)s16X[ChOffset+48+2];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_2_3*(SINT32)s16X[ChOffset+16+14];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_2_4*(SINT32)s16X[ChOffset+64+2];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_2_4*(SINT32)s16X[ChOffset+14];\ + s32DCTY[2]=(SINT32)s32Temp;\ + s32DCTY[14]=(SINT32)s32Temp2;\ +} +#define WINDOW_ACCU_8_3_13 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_3_0*(SINT32)s16X[ChOffset+3];\ + s32Temp2=(SINT32)WIND_8_SUBBANDS_3_0*(SINT32)s16X[ChOffset+64+13];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_3_1*(SINT32)s16X[ChOffset+16+3];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_3_1*(SINT32)s16X[ChOffset+48+13];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_3_2*(SINT32)s16X[ChOffset+32+3];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_3_2*(SINT32)s16X[ChOffset+32+13];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_3_3*(SINT32)s16X[ChOffset+48+3];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_3_3*(SINT32)s16X[ChOffset+16+13];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_3_4*(SINT32)s16X[ChOffset+64+3];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_3_4*(SINT32)s16X[ChOffset+13];\ + s32DCTY[3]=(SINT32)s32Temp;\ + s32DCTY[13]=(SINT32)s32Temp2;\ +} +#define WINDOW_ACCU_8_4_12 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_4_0*(SINT32)s16X[ChOffset+4];\ + s32Temp2=(SINT32)WIND_8_SUBBANDS_4_0*(SINT32)s16X[ChOffset+64+12];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_4_1*(SINT32)s16X[ChOffset+16+4];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_4_1*(SINT32)s16X[ChOffset+48+12];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_4_2*(SINT32)s16X[ChOffset+32+4];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_4_2*(SINT32)s16X[ChOffset+32+12];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_4_3*(SINT32)s16X[ChOffset+48+4];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_4_3*(SINT32)s16X[ChOffset+16+12];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_4_4*(SINT32)s16X[ChOffset+64+4];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_4_4*(SINT32)s16X[ChOffset+12];\ + s32DCTY[4]=(SINT32)s32Temp;\ + s32DCTY[12]=(SINT32)s32Temp2;\ +} +#define WINDOW_ACCU_8_5_11 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_5_0*(SINT32)s16X[ChOffset+5];\ + s32Temp2=(SINT32)WIND_8_SUBBANDS_5_0*(SINT32)s16X[ChOffset+64+11];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_5_1*(SINT32)s16X[ChOffset+16+5];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_5_1*(SINT32)s16X[ChOffset+48+11];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_5_2*(SINT32)s16X[ChOffset+32+5];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_5_2*(SINT32)s16X[ChOffset+32+11];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_5_3*(SINT32)s16X[ChOffset+48+5];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_5_3*(SINT32)s16X[ChOffset+16+11];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_5_4*(SINT32)s16X[ChOffset+64+5];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_5_4*(SINT32)s16X[ChOffset+11];\ + s32DCTY[5]=(SINT32)s32Temp;\ + s32DCTY[11]=(SINT32)s32Temp2;\ +} +#define WINDOW_ACCU_8_6_10 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_6_0*(SINT32)s16X[ChOffset+6];\ + s32Temp2=(SINT32)WIND_8_SUBBANDS_6_0*(SINT32)s16X[ChOffset+64+10];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_6_1*(SINT32)s16X[ChOffset+16+6];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_6_1*(SINT32)s16X[ChOffset+48+10];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_6_2*(SINT32)s16X[ChOffset+32+6];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_6_2*(SINT32)s16X[ChOffset+32+10];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_6_3*(SINT32)s16X[ChOffset+48+6];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_6_3*(SINT32)s16X[ChOffset+16+10];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_6_4*(SINT32)s16X[ChOffset+64+6];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_6_4*(SINT32)s16X[ChOffset+10];\ + s32DCTY[6]=(SINT32)s32Temp;\ + s32DCTY[10]=(SINT32)s32Temp2;\ +} +#define WINDOW_ACCU_8_7_9 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_7_0*(SINT32)s16X[ChOffset+7];\ + s32Temp2=(SINT32)WIND_8_SUBBANDS_7_0*(SINT32)s16X[ChOffset+64+9];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_7_1*(SINT32)s16X[ChOffset+16+7];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_7_1*(SINT32)s16X[ChOffset+48+9];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_7_2*(SINT32)s16X[ChOffset+32+7];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_7_2*(SINT32)s16X[ChOffset+32+9];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_7_3*(SINT32)s16X[ChOffset+48+7];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_7_3*(SINT32)s16X[ChOffset+16+9];\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_7_4*(SINT32)s16X[ChOffset+64+7];\ + s32Temp2+=(SINT32)WIND_8_SUBBANDS_7_4*(SINT32)s16X[ChOffset+9];\ + s32DCTY[7]=(SINT32)s32Temp;\ + s32DCTY[9]=(SINT32)s32Temp2;\ +} +#define WINDOW_ACCU_8_8 \ +{\ + s32Temp=(SINT32)WIND_8_SUBBANDS_8_0*(SINT32)(s16X[ChOffset+8]+s16X[ChOffset+64+8]);\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_8_1*(SINT32)(s16X[ChOffset+16+8]+s16X[ChOffset+48+8]);\ + s32Temp+=(SINT32)WIND_8_SUBBANDS_8_2*(SINT32)s16X[ChOffset+32+8];\ + s32DCTY[8]=(SINT32)s32Temp;\ +} +#define WINDOW_ACCU_4_0 \ +{\ + s32Temp=(SINT32)WIND_4_SUBBANDS_0_1*(SINT32)(s16X[ChOffset+8]-s16X[ChOffset+32]);\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_0_2*(SINT32)(s16X[ChOffset+16]-s16X[ChOffset+24]);\ + s32DCTY[0]=(SINT32)(s32Temp);\ +} +#define WINDOW_ACCU_4_1_7 \ +{\ + s32Temp=(SINT32)WIND_4_SUBBANDS_1_0*(SINT32)s16X[ChOffset+1];\ + s32Temp2=(SINT32)WIND_4_SUBBANDS_1_0*(SINT32)s16X[ChOffset+32+7];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_1_1*(SINT32)s16X[ChOffset+8+1];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_1_1*(SINT32)s16X[ChOffset+24+7];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_1_2*(SINT32)s16X[ChOffset+16+1];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_1_2*(SINT32)s16X[ChOffset+16+7];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_1_3*(SINT32)s16X[ChOffset+24+1];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_1_3*(SINT32)s16X[ChOffset+8+7];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_1_4*(SINT32)s16X[ChOffset+32+1];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_1_4*(SINT32)s16X[ChOffset+7];\ + s32DCTY[1]=(SINT32)(s32Temp);\ + s32DCTY[7]=(SINT32)(s32Temp2);\ +} +#define WINDOW_ACCU_4_2_6 \ +{\ + s32Temp=(SINT32)WIND_4_SUBBANDS_2_0*(SINT32)s16X[ChOffset+2];\ + s32Temp2=(SINT32)WIND_4_SUBBANDS_2_0*(SINT32)s16X[ChOffset+32+6];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_2_1*(SINT32)s16X[ChOffset+8+2];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_2_1*(SINT32)s16X[ChOffset+24+6];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_2_2*(SINT32)s16X[ChOffset+16+2];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_2_2*(SINT32)s16X[ChOffset+16+6];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_2_3*(SINT32)s16X[ChOffset+24+2];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_2_3*(SINT32)s16X[ChOffset+8+6];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_2_4*(SINT32)s16X[ChOffset+32+2];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_2_4*(SINT32)s16X[ChOffset+6];\ + s32DCTY[2]=(SINT32)(s32Temp);\ + s32DCTY[6]=(SINT32)(s32Temp2);\ +} +#define WINDOW_ACCU_4_3_5 \ +{\ + s32Temp=(SINT32)WIND_4_SUBBANDS_3_0*(SINT32)s16X[ChOffset+3];\ + s32Temp2=(SINT32)WIND_4_SUBBANDS_3_0*(SINT32)s16X[ChOffset+32+5];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_3_1*(SINT32)s16X[ChOffset+8+3];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_3_1*(SINT32)s16X[ChOffset+24+5];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_3_2*(SINT32)s16X[ChOffset+16+3];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_3_2*(SINT32)s16X[ChOffset+16+5];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_3_3*(SINT32)s16X[ChOffset+24+3];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_3_3*(SINT32)s16X[ChOffset+8+5];\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_3_4*(SINT32)s16X[ChOffset+32+3];\ + s32Temp2+=(SINT32)WIND_4_SUBBANDS_3_4*(SINT32)s16X[ChOffset+5];\ + s32DCTY[3]=(SINT32)(s32Temp);\ + s32DCTY[5]=(SINT32)(s32Temp2);\ +} + +#define WINDOW_ACCU_4_4 \ +{\ + s32Temp=(SINT32)WIND_4_SUBBANDS_4_0*(SINT32)(s16X[ChOffset+4]+s16X[ChOffset+4+32]);\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_4_1*(SINT32)(s16X[ChOffset+4+8]+s16X[ChOffset+4+24]);\ + s32Temp+=(SINT32)WIND_4_SUBBANDS_4_2*(SINT32)s16X[ChOffset+4+16];\ + s32DCTY[4]=(SINT32)(s32Temp);\ +} +#endif +#define WINDOW_PARTIAL_4 \ +{\ + WINDOW_ACCU_4_0; WINDOW_ACCU_4_1_7;\ + WINDOW_ACCU_4_2_6; WINDOW_ACCU_4_3_5;\ + WINDOW_ACCU_4_4;\ +} + +#define WINDOW_PARTIAL_8 \ +{\ + WINDOW_ACCU_8_0; WINDOW_ACCU_8_1_15;\ + WINDOW_ACCU_8_2_14; WINDOW_ACCU_8_3_13;\ + WINDOW_ACCU_8_4_12; WINDOW_ACCU_8_5_11;\ + WINDOW_ACCU_8_6_10; WINDOW_ACCU_8_7_9;\ + WINDOW_ACCU_8_8;\ +} +#else +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) +#define WINDOW_ACCU_4(i) \ +{\ + s64Temp=((SINT64)gas32CoeffFor4SBs[i] * (SINT64)s16X[ChOffset+i]); \ + s64Temp+=((SINT64)gas32CoeffFor4SBs[(i+8)] * (SINT64)s16X[ChOffset+i+8]); \ + s64Temp+=((SINT64)gas32CoeffFor4SBs[(i+16)] * (SINT64)s16X[ChOffset+i+16]); \ + s64Temp+=((SINT64)gas32CoeffFor4SBs[(i+24)] * (SINT64)s16X[ChOffset+i+24]); \ + s64Temp+=((SINT64)gas32CoeffFor4SBs[(i+32)] * (SINT64)s16X[ChOffset+i+32]); \ + s32DCTY[i]=(SINT32)(s64Temp>>16);\ + /*printf("s32DCTY4: 0x%x \n", s32DCTY[i]);*/\ +} +#else +#define WINDOW_ACCU_4(i) \ +{\ + s32DCTY[i]=(gas32CoeffFor4SBs[i * 2] * s16X[ChOffset+i]) \ + + (((SINT32)(UINT16)(gas32CoeffFor4SBs[(i * 2) + 1]) * s16X[ChOffset+i]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor4SBs[(i+8) * 2] * s16X[ChOffset+i+8]) \ + + (((SINT32)(UINT16)(gas32CoeffFor4SBs[((i+8) * 2) + 1]) * s16X[ChOffset+i+8]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor4SBs[(i+16) * 2] * s16X[ChOffset+i+16]) \ + + (((SINT32)(UINT16)(gas32CoeffFor4SBs[((i+16) * 2) + 1]) * s16X[ChOffset+i+16]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor4SBs[(i+24) * 2] * s16X[ChOffset+i+24]) \ + + (((SINT32)(UINT16)(gas32CoeffFor4SBs[((i+24) * 2) + 1]) * s16X[ChOffset+i+24]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor4SBs[(i+32) * 2] * s16X[ChOffset+i+32]) \ + + (((SINT32)(UINT16)(gas32CoeffFor4SBs[((i+32) * 2) + 1]) * s16X[ChOffset+i+32]) >> 16); \ +} +#endif +#define WINDOW_PARTIAL_4 \ +{\ + WINDOW_ACCU_4(0); WINDOW_ACCU_4(1);\ + WINDOW_ACCU_4(2); WINDOW_ACCU_4(3);\ + WINDOW_ACCU_4(4); WINDOW_ACCU_4(5);\ + WINDOW_ACCU_4(6); WINDOW_ACCU_4(7);\ +} + +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) +#define WINDOW_ACCU_8(i) \ +{\ + s64Temp = ((((SINT64)gas32CoeffFor8SBs[i] * (SINT64)s16X[ChOffset+i] ))); \ + s64Temp+= ((((SINT64)gas32CoeffFor8SBs[(i+16)] * (SINT64)s16X[ChOffset+i+16]))); \ + s64Temp+= ((((SINT64)gas32CoeffFor8SBs[(i+32)] * (SINT64)s16X[ChOffset+i+32]))); \ + s64Temp+= ((((SINT64)gas32CoeffFor8SBs[(i+48)] * (SINT64)s16X[ChOffset+i+48]))); \ + s64Temp+= ((((SINT64)gas32CoeffFor8SBs[(i+64)] * (SINT64)s16X[ChOffset+i+64]))); \ + /*printf("s32DCTY8: %d= 0x%x * %d\n", s32DCTY[i], gas32CoeffFor8SBs[i], s16X[ChOffset+i]);*/ \ + s32DCTY[i]=(SINT32)(s64Temp>>16);\ +} +#else +#define WINDOW_ACCU_8(i) \ +{\ + s32DCTY[i]=(gas32CoeffFor8SBs[i * 2] * s16X[ChOffset+i]) \ + + (((SINT32)(UINT16)(gas32CoeffFor8SBs[(i * 2) + 1]) * s16X[ChOffset+i]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor8SBs[(i+16) * 2] * s16X[ChOffset+i+16]) \ + + (((SINT32)(UINT16)(gas32CoeffFor8SBs[((i+16) * 2) + 1]) * s16X[ChOffset+i+16]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor8SBs[(i+32) * 2] * s16X[ChOffset+i+32]) \ + + (((SINT32)(UINT16)(gas32CoeffFor8SBs[((i+32) * 2) + 1]) * s16X[ChOffset+i+32]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor8SBs[(i+48) * 2] * s16X[ChOffset+i+48]) \ + + (((SINT32)(UINT16)(gas32CoeffFor8SBs[((i+48) * 2) + 1]) * s16X[ChOffset+i+48]) >> 16); \ + s32DCTY[i]+=(gas32CoeffFor8SBs[(i+64) * 2] * s16X[ChOffset+i+64]) \ + + (((SINT32)(UINT16)(gas32CoeffFor8SBs[((i+64) * 2) + 1]) * s16X[ChOffset+i+64]) >> 16); \ + /*printf("s32DCTY8: %d = 0x%4x%4x * %d\n", s32DCTY[i], gas32CoeffFor8SBs[i * 2], (gas32CoeffFor8SBs[(i * 2) + 1]), s16X[ChOffset+i]);*/\ + /*s32DCTY[i]=(SINT32)(s64Temp>>16);*/\ +} +#endif +#define WINDOW_PARTIAL_8 \ +{\ + WINDOW_ACCU_8(0); WINDOW_ACCU_8(1);\ + WINDOW_ACCU_8(2); WINDOW_ACCU_8(3);\ + WINDOW_ACCU_8(4); WINDOW_ACCU_8(5);\ + WINDOW_ACCU_8(6); WINDOW_ACCU_8(7);\ + WINDOW_ACCU_8(8); WINDOW_ACCU_8(9);\ + WINDOW_ACCU_8(10); WINDOW_ACCU_8(11);\ + WINDOW_ACCU_8(12); WINDOW_ACCU_8(13);\ + WINDOW_ACCU_8(14); WINDOW_ACCU_8(15);\ +} +#endif +#endif + +static SINT16 ShiftCounter = 0; +extern SINT16 EncMaxShiftCounter; +/**************************************************************************** +* SbcAnalysisFilter - performs Analysis of the input audio stream +* +* RETURNS : N/A +*/ +void SbcAnalysisFilter4(SBC_ENC_PARAMS *pstrEncParams) +{ + SINT16 *ps16PcmBuf; + SINT32 *ps32SbBuf; + SINT32 s32Blk, s32Ch; + SINT32 s32NumOfChannels, s32NumOfBlocks; + SINT32 i, *ps32X, *ps32X2; + SINT32 Offset, Offset2, ChOffset; +#if (SBC_ARM_ASM_OPT==TRUE) + register SINT32 s32Hi, s32Hi2; +#else +#if (SBC_IPAQ_OPT==TRUE) +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) + register SINT64 s64Temp, s64Temp2; +#else + register SINT32 s32Temp, s32Temp2; +#endif +#else + +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) + SINT64 s64Temp; +#endif + +#endif +#endif + + s32NumOfChannels = pstrEncParams->s16NumOfChannels; + s32NumOfBlocks = pstrEncParams->s16NumOfBlocks; + + ps16PcmBuf = pstrEncParams->ps16NextPcmBuffer; + + ps32SbBuf = pstrEncParams->s32SbBuffer; + Offset2 = (SINT32)(EncMaxShiftCounter + 40); + for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) { + Offset = (SINT32)(EncMaxShiftCounter - ShiftCounter); + /* Store new samples */ + if (s32NumOfChannels == 1) { + s16X[3 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[2 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[1 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[0 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + } else { + s16X[3 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 3 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[2 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 2 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[1 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 1 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[0 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 0 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + } + for (s32Ch = 0; s32Ch < s32NumOfChannels; s32Ch++) { + ChOffset = s32Ch * Offset2 + Offset; + + WINDOW_PARTIAL_4 + + SBC_FastIDCT4(s32DCTY, ps32SbBuf); + + ps32SbBuf += SUB_BANDS_4; + } + if (s32NumOfChannels == 1) { + if (ShiftCounter >= EncMaxShiftCounter) { + SHIFTUP_X4; + ShiftCounter = 0; + } else { + ShiftCounter += SUB_BANDS_4; + } + } else { + if (ShiftCounter >= EncMaxShiftCounter) { + SHIFTUP_X4_2; + ShiftCounter = 0; + } else { + ShiftCounter += SUB_BANDS_4; + } + } + } +} + +/* //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */ +void SbcAnalysisFilter8 (SBC_ENC_PARAMS *pstrEncParams) +{ + SINT16 *ps16PcmBuf; + SINT32 *ps32SbBuf; + SINT32 s32Blk, s32Ch; /* counter for block*/ + SINT32 Offset, Offset2; + SINT32 s32NumOfChannels, s32NumOfBlocks; + SINT32 i, *ps32X, *ps32X2; + SINT32 ChOffset; +#if (SBC_ARM_ASM_OPT==TRUE) + register SINT32 s32Hi, s32Hi2; +#else +#if (SBC_IPAQ_OPT==TRUE) +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) + register SINT64 s64Temp, s64Temp2; +#else + register SINT32 s32Temp, s32Temp2; +#endif +#else +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == TRUE) + SINT64 s64Temp; +#endif +#endif +#endif + + s32NumOfChannels = pstrEncParams->s16NumOfChannels; + s32NumOfBlocks = pstrEncParams->s16NumOfBlocks; + + ps16PcmBuf = pstrEncParams->ps16NextPcmBuffer; + + ps32SbBuf = pstrEncParams->s32SbBuffer; + Offset2 = (SINT32)(EncMaxShiftCounter + 80); + for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) { + Offset = (SINT32)(EncMaxShiftCounter - ShiftCounter); + /* Store new samples */ + if (s32NumOfChannels == 1) { + s16X[7 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[6 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[5 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[4 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[3 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[2 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[1 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[0 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + } else { + s16X[7 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 7 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[6 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 6 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[5 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 5 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[4 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 4 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[3 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 3 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[2 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 2 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[1 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 1 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[0 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + s16X[Offset2 + 0 + Offset] = *ps16PcmBuf; ps16PcmBuf++; + } + for (s32Ch = 0; s32Ch < s32NumOfChannels; s32Ch++) { + ChOffset = s32Ch * Offset2 + Offset; + + WINDOW_PARTIAL_8 + + SBC_FastIDCT8 (s32DCTY, ps32SbBuf); + + ps32SbBuf += SUB_BANDS_8; + } + if (s32NumOfChannels == 1) { + if (ShiftCounter >= EncMaxShiftCounter) { + SHIFTUP_X8; + ShiftCounter = 0; + } else { + ShiftCounter += SUB_BANDS_8; + } + } else { + if (ShiftCounter >= EncMaxShiftCounter) { + SHIFTUP_X8_2; + ShiftCounter = 0; + } else { + ShiftCounter += SUB_BANDS_8; + } + } + } +} + +void SbcAnalysisInit (void) +{ + memset(s16X, 0, ENC_VX_BUFFER_SIZE * sizeof(SINT16)); + ShiftCounter = 0; +} + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct.c new file mode 100644 index 0000000000..23ddd386ca --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct.c @@ -0,0 +1,244 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * source file for fast dct operations + * + ******************************************************************************/ +#include "bt_target.h" +#include "sbc_encoder.h" +#include "sbc_enc_func_declare.h" +#include "sbc_dct.h" + + +#if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function SBC_FastIDCT8 +** +** Description implementation of fast DCT algorithm by Feig and Winograd +** +** +** Returns y = dct(pInVect) +** +** +*******************************************************************************/ + +#if (SBC_IS_64_MULT_IN_IDCT == FALSE) +#define SBC_COS_PI_SUR_4 (0x00005a82) /* ((0x8000) * 0.7071) = cos(pi/4) */ +#define SBC_COS_PI_SUR_8 (0x00007641) /* ((0x8000) * 0.9239) = (cos(pi/8)) */ +#define SBC_COS_3PI_SUR_8 (0x000030fb) /* ((0x8000) * 0.3827) = (cos(3*pi/8)) */ +#define SBC_COS_PI_SUR_16 (0x00007d8a) /* ((0x8000) * 0.9808)) = (cos(pi/16)) */ +#define SBC_COS_3PI_SUR_16 (0x00006a6d) /* ((0x8000) * 0.8315)) = (cos(3*pi/16)) */ +#define SBC_COS_5PI_SUR_16 (0x0000471c) /* ((0x8000) * 0.5556)) = (cos(5*pi/16)) */ +#define SBC_COS_7PI_SUR_16 (0x000018f8) /* ((0x8000) * 0.1951)) = (cos(7*pi/16)) */ +#define SBC_IDCT_MULT(a,b,c) SBC_MULT_32_16_SIMPLIFIED(a,b,c) +#else +#define SBC_COS_PI_SUR_4 (0x5A827999) /* ((0x80000000) * 0.707106781) = (cos(pi/4) ) */ +#define SBC_COS_PI_SUR_8 (0x7641AF3C) /* ((0x80000000) * 0.923879533) = (cos(pi/8) ) */ +#define SBC_COS_3PI_SUR_8 (0x30FBC54D) /* ((0x80000000) * 0.382683432) = (cos(3*pi/8) ) */ +#define SBC_COS_PI_SUR_16 (0x7D8A5F3F) /* ((0x80000000) * 0.98078528 )) = (cos(pi/16) ) */ +#define SBC_COS_3PI_SUR_16 (0x6A6D98A4) /* ((0x80000000) * 0.831469612)) = (cos(3*pi/16)) */ +#define SBC_COS_5PI_SUR_16 (0x471CECE6) /* ((0x80000000) * 0.555570233)) = (cos(5*pi/16)) */ +#define SBC_COS_7PI_SUR_16 (0x18F8B83C) /* ((0x80000000) * 0.195090322)) = (cos(7*pi/16)) */ +#define SBC_IDCT_MULT(a,b,c) SBC_MULT_32_32(a,b,c) +#endif /* SBC_IS_64_MULT_IN_IDCT */ + +#if (SBC_FAST_DCT == FALSE) +extern const SINT16 gas16AnalDCTcoeff8[]; +extern const SINT16 gas16AnalDCTcoeff4[]; +#endif + +void SBC_FastIDCT8(SINT32 *pInVect, SINT32 *pOutVect) +{ +#if (SBC_FAST_DCT == TRUE) +#if (SBC_ARM_ASM_OPT==TRUE) +#else +#if (SBC_IPAQ_OPT==TRUE) +#if (SBC_IS_64_MULT_IN_IDCT == TRUE) + SINT64 s64Temp; +#endif +#else +#if (SBC_IS_64_MULT_IN_IDCT == TRUE) + SINT32 s32HiTemp; +#else + SINT32 s32In2Temp; + register SINT32 s32In1Temp; +#endif +#endif +#endif + + register SINT32 x0, x1, x2, x3, x4, x5, x6, x7, temp; + SINT32 res_even[4], res_odd[4]; + /*x0= (pInVect[4])/2 ;*/ + SBC_IDCT_MULT(SBC_COS_PI_SUR_4, pInVect[4], x0); + /*printf("x0 0x%x = %d = %d * %d\n", x0, x0, SBC_COS_PI_SUR_4, pInVect[4]);*/ + + x1 = (pInVect[3] + pInVect[5]) >> 1; + x2 = (pInVect[2] + pInVect[6]) >> 1; + x3 = (pInVect[1] + pInVect[7]) >> 1; + x4 = (pInVect[0] + pInVect[8]) >> 1; + x5 = (pInVect[9] - pInVect[15]) >> 1; + x6 = (pInVect[10] - pInVect[14]) >> 1; + x7 = (pInVect[11] - pInVect[13]) >> 1; + + /* 2-point IDCT of x0 and x4 as in (11) */ + temp = x0 ; + SBC_IDCT_MULT(SBC_COS_PI_SUR_4, ( x0 + x4 ), x0); /*x0 = ( x0 + x4 ) * cos(1*pi/4) ; */ + SBC_IDCT_MULT(SBC_COS_PI_SUR_4, ( temp - x4 ), x4); /*x4 = ( temp - x4 ) * cos(1*pi/4) ; */ + + /* rearrangement of x2 and x6 as in (15) */ + x2 -= x6; + x6 <<= 1 ; + + /* 2-point IDCT of x2 and x6 and post-multiplication as in (15) */ + SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x6, x6); /*x6 = x6 * cos(1*pi/4) ; */ + temp = x2 ; + SBC_IDCT_MULT(SBC_COS_PI_SUR_8, ( x2 + x6 ), x2); /*x2 = ( x2 + x6 ) * cos(1*pi/8) ; */ + SBC_IDCT_MULT(SBC_COS_3PI_SUR_8, ( temp - x6 ), x6); /*x6 = ( temp - x6 ) * cos(3*pi/8) ;*/ + + /* 4-point IDCT of x0,x2,x4 and x6 as in (11) */ + res_even[ 0 ] = x0 + x2 ; + res_even[ 1 ] = x4 + x6 ; + res_even[ 2 ] = x4 - x6 ; + res_even[ 3 ] = x0 - x2 ; + + + /* rearrangement of x1,x3,x5,x7 as in (15) */ + x7 <<= 1 ; + x5 = ( x5 << 1 ) - x7 ; + x3 = ( x3 << 1 ) - x5 ; + x1 -= x3 >> 1 ; + + /* two-dimensional IDCT of x1 and x5 */ + SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x5, x5); /*x5 = x5 * cos(1*pi/4) ; */ + temp = x1 ; + x1 = x1 + x5 ; + x5 = temp - x5 ; + + /* rearrangement of x3 and x7 as in (15) */ + x3 -= x7; + x7 <<= 1 ; + SBC_IDCT_MULT(SBC_COS_PI_SUR_4, x7, x7); /*x7 = x7 * cos(1*pi/4) ; */ + + /* 2-point IDCT of x3 and x7 and post-multiplication as in (15) */ + temp = x3 ; + SBC_IDCT_MULT( SBC_COS_PI_SUR_8, ( x3 + x7 ), x3); /*x3 = ( x3 + x7 ) * cos(1*pi/8) ; */ + SBC_IDCT_MULT( SBC_COS_3PI_SUR_8, ( temp - x7 ), x7); /*x7 = ( temp - x7 ) * cos(3*pi/8) ;*/ + + /* 4-point IDCT of x1,x3,x5 and x7 and post multiplication by diagonal matrix as in (14) */ + SBC_IDCT_MULT((SBC_COS_PI_SUR_16), ( x1 + x3 ) , res_odd[0]); /*res_odd[ 0 ] = ( x1 + x3 ) * cos(1*pi/16) ; */ + SBC_IDCT_MULT((SBC_COS_3PI_SUR_16), ( x5 + x7 ) , res_odd[1]); /*res_odd[ 1 ] = ( x5 + x7 ) * cos(3*pi/16) ; */ + SBC_IDCT_MULT((SBC_COS_5PI_SUR_16), ( x5 - x7 ) , res_odd[2]); /*res_odd[ 2 ] = ( x5 - x7 ) * cos(5*pi/16) ; */ + SBC_IDCT_MULT((SBC_COS_7PI_SUR_16), ( x1 - x3 ) , res_odd[3]); /*res_odd[ 3 ] = ( x1 - x3 ) * cos(7*pi/16) ; */ + + /* additions and subtractions as in (9) */ + pOutVect[0] = (res_even[ 0 ] + res_odd[ 0 ]) ; + pOutVect[1] = (res_even[ 1 ] + res_odd[ 1 ]) ; + pOutVect[2] = (res_even[ 2 ] + res_odd[ 2 ]) ; + pOutVect[3] = (res_even[ 3 ] + res_odd[ 3 ]) ; + pOutVect[7] = (res_even[ 0 ] - res_odd[ 0 ]) ; + pOutVect[6] = (res_even[ 1 ] - res_odd[ 1 ]) ; + pOutVect[5] = (res_even[ 2 ] - res_odd[ 2 ]) ; + pOutVect[4] = (res_even[ 3 ] - res_odd[ 3 ]) ; +#else + UINT8 Index, k; + SINT32 temp; + /*Calculate 4 subband samples by matrixing*/ + for (Index = 0; Index < 8; Index++) { + temp = 0; + for (k = 0; k < 16; k++) { + /*temp += (SINT32)(((SINT64)M[(Index*strEncParams->numOfSubBands*2)+k] * Y[k]) >> 16 );*/ + temp += (gas16AnalDCTcoeff8[(Index * 8 * 2) + k] * (pInVect[k] >> 16)); + temp += ((gas16AnalDCTcoeff8[(Index * 8 * 2) + k] * (pInVect[k] & 0xFFFF)) >> 16); + } + pOutVect[Index] = temp; + } +#endif + /* printf("pOutVect: 0x%x;0x%x;0x%x;0x%x;0x%x;0x%x;0x%x;0x%x\n",\ + pOutVect[0],pOutVect[1],pOutVect[2],pOutVect[3],pOutVect[4],pOutVect[5],pOutVect[6],pOutVect[7]);*/ +} + +/******************************************************************************* +** +** Function SBC_FastIDCT4 +** +** Description implementation of fast DCT algorithm by Feig and Winograd +** +** +** Returns y = dct(x0) +** +** +*******************************************************************************/ +void SBC_FastIDCT4(SINT32 *pInVect, SINT32 *pOutVect) +{ +#if (SBC_FAST_DCT == TRUE) +#if (SBC_ARM_ASM_OPT==TRUE) +#else +#if (SBC_IPAQ_OPT==TRUE) +#if (SBC_IS_64_MULT_IN_IDCT == TRUE) + SINT64 s64Temp; +#endif +#else +#if (SBC_IS_64_MULT_IN_IDCT == TRUE) + SINT32 s32HiTemp; +#else + UINT16 s32In2Temp; + SINT32 s32In1Temp; +#endif +#endif +#endif + SINT32 temp, x2; + SINT32 tmp[8]; + + x2 = pInVect[2] >> 1; + temp = (pInVect[0] + pInVect[4]); + SBC_IDCT_MULT((SBC_COS_PI_SUR_4 >> 1), temp , tmp[0]); + tmp[1] = x2 - tmp[0]; + tmp[0] += x2; + temp = (pInVect[1] + pInVect[3]); + SBC_IDCT_MULT((SBC_COS_3PI_SUR_8 >> 1), temp , tmp[3]); + SBC_IDCT_MULT((SBC_COS_PI_SUR_8 >> 1), temp , tmp[2]); + temp = (pInVect[5] - pInVect[7]); + SBC_IDCT_MULT((SBC_COS_3PI_SUR_8 >> 1), temp , tmp[5]); + SBC_IDCT_MULT((SBC_COS_PI_SUR_8 >> 1), temp , tmp[4]); + tmp[6] = tmp[2] + tmp[5]; + tmp[7] = tmp[3] - tmp[4]; + pOutVect[0] = (tmp[0] + tmp[6]); + pOutVect[1] = (tmp[1] + tmp[7]); + pOutVect[2] = (tmp[1] - tmp[7]); + pOutVect[3] = (tmp[0] - tmp[6]); +#else + UINT8 Index, k; + SINT32 temp; + /*Calculate 4 subband samples by matrixing*/ + for (Index = 0; Index < 4; Index++) { + temp = 0; + for (k = 0; k < 8; k++) { + /*temp += (SINT32)(((SINT64)M[(Index*strEncParams->numOfSubBands*2)+k] * Y[k]) >> 16 ); */ + temp += (gas16AnalDCTcoeff4[(Index * 4 * 2) + k] * (pInVect[k] >> 16)); + temp += ((gas16AnalDCTcoeff4[(Index * 4 * 2) + k] * (pInVect[k] & 0xFFFF)) >> 16); + } + pOutVect[Index] = temp; + } +#endif +} + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c new file mode 100644 index 0000000000..671ca4bab8 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_dct_coeffs.c @@ -0,0 +1,203 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the coefficient table used for DCT computation in + * analysis. + * + ******************************************************************************/ +#include "bt_target.h" +#include "sbc_encoder.h" + +#if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) + +/*DCT coeff for 4 sub-band case.*/ +#if (SBC_FAST_DCT == FALSE) +const SINT16 gas16AnalDCTcoeff4[] = { + (SINT16)(0.7071 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(0.9239 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(0.0000 * 32768), + (SINT16)(-0.3827 * 32768), + + (SINT16)(-0.7071 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(0.3827 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(-0.0000 * 32768), + (SINT16)(0.9239 * 32768), + + (SINT16)(-0.7071 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(-0.3827 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(0.0000 * 32768), + (SINT16)(-0.9239 * 32768), + + (SINT16)(0.7071 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(-0.9239 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(-0.0000 * 32768), + (SINT16)(0.3827 * 32768) +}; + +/*DCT coeff for 8 sub-band case.*/ +const SINT16 gas16AnalDCTcoeff8[] = { + (SINT16)(0.7071 * 32768), + (SINT16)(0.8315 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(0.9808 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(0.9808 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(0.8315 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(0.5556 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(0.1951 * 32768), + (SINT16)(0.0000 * 32768), + (SINT16)(-0.1951 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(-0.5556 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(-0.1951 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(0.8315 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(0.8315 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(-0.1951 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(-0.9808 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(-0.5556 * 32768), + (SINT16)(-0.0000 * 32768), + (SINT16)(0.5556 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(0.9808 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(-0.9808 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(0.5556 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(0.5556 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(-0.9808 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(0.1951 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(0.8315 * 32768), + (SINT16)(0.0000 * 32768), + (SINT16)(-0.8315 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(-0.1951 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(-0.5556 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(0.1951 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(0.1951 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(-0.5556 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(0.8315 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(-0.9808 * 32768), + (SINT16)(-0.0000 * 32768), + (SINT16)(0.9808 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(-0.8315 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(0.5556 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(-0.1951 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(-0.1951 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(0.5556 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(-0.8315 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(0.9808 * 32768), + (SINT16)(0.0000 * 32768), + (SINT16)(-0.9808 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(0.8315 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(0.9808 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(-0.5556 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(-0.5556 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(0.9808 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(-0.1951 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(-0.8315 * 32768), + (SINT16)(-0.0000 * 32768), + (SINT16)(0.8315 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(0.1951 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(0.1951 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(-0.8315 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(-0.8315 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(0.1951 * 32768), + (SINT16)(-0.7071 * 32768), + (SINT16)(0.9808 * 32768), + (SINT16)(-0.9239 * 32768), + (SINT16)(0.5556 * 32768), + (SINT16)(-0.0000 * 32768), + (SINT16)(-0.5556 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(-0.9808 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(-0.8315 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(-0.9808 * 32768), + (SINT16)(1.0000 * 32767), + (SINT16)(-0.9808 * 32768), + (SINT16)(0.9239 * 32768), + (SINT16)(-0.8315 * 32768), + (SINT16)(0.7071 * 32768), + (SINT16)(-0.5556 * 32768), + (SINT16)(0.3827 * 32768), + (SINT16)(-0.1951 * 32768), + (SINT16)(-0.0000 * 32768), + (SINT16)(0.1951 * 32768), + (SINT16)(-0.3827 * 32768), + (SINT16)(0.5556 * 32768) +}; +#endif + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c new file mode 100644 index 0000000000..d4a1e84477 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_mono.c @@ -0,0 +1,188 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the code for bit allocation algorithm. It calculates + * the number of bits required for the encoded stream of data. + * + ******************************************************************************/ + +/*Includes*/ +#include "bt_target.h" +#include "sbc_encoder.h" +#include "sbc_enc_func_declare.h" + +#if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) + +/*global arrays*/ +const SINT16 sbc_enc_as16Offset4[4][4] = { { -1, 0, 0, 0}, { -2, 0, 0, 1}, + { -2, 0, 0, 1}, { -2, 0, 0, 1} +}; +const SINT16 sbc_enc_as16Offset8[4][8] = { { -2, 0, 0, 0, 0, 0, 0, 1}, + { -3, 0, 0, 0, 0, 0, 1, 2}, + { -4, 0, 0, 0, 0, 0, 1, 2}, + { -4, 0, 0, 0, 0, 0, 1, 2} +}; + +/**************************************************************************** +* BitAlloc - Calculates the required number of bits for the given scale factor +* and the number of subbands. +* +* RETURNS : N/A +*/ + +void sbc_enc_bit_alloc_mono(SBC_ENC_PARAMS *pstrCodecParams) +{ + SINT32 s32MaxBitNeed; /*to store the max bits needed per sb*/ + SINT32 s32BitCount; /*the used number of bits*/ + SINT32 s32SliceCount; /*to store hwo many slices can be put in bitpool*/ + SINT32 s32BitSlice; /*number of bitslices in bitpool*/ + SINT32 s32Sb; /*counter for sub-band*/ + SINT32 s32Ch; /*counter for channel*/ + SINT16 *ps16BitNeed; /*temp memory to store required number of bits*/ + SINT32 s32Loudness; /*used in Loudness calculation*/ + SINT16 *ps16GenBufPtr; + SINT16 *ps16GenArrPtr; + SINT16 *ps16GenTabPtr; + SINT32 s32NumOfSubBands = pstrCodecParams->s16NumOfSubBands; + + ps16BitNeed = pstrCodecParams->s16ScartchMemForBitAlloc; + + for (s32Ch = 0; s32Ch < pstrCodecParams->s16NumOfChannels; s32Ch++) { + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * SBC_MAX_NUM_OF_SUBBANDS; + + /* bitneed values are derived from scale factor */ + if (pstrCodecParams->s16AllocationMethod == SBC_SNR) { + ps16BitNeed = pstrCodecParams->as16ScaleFactor; + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + } else { + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + if (s32NumOfSubBands == 4) { + ps16GenTabPtr = (SINT16 *) + sbc_enc_as16Offset4[pstrCodecParams->s16SamplingFreq]; + } else { + ps16GenTabPtr = (SINT16 *) + sbc_enc_as16Offset8[pstrCodecParams->s16SamplingFreq]; + } + for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) { + if (pstrCodecParams->as16ScaleFactor[s32Ch * s32NumOfSubBands + s32Sb] == 0) { + *(ps16GenBufPtr) = -5; + } else { + s32Loudness = + (SINT32)(pstrCodecParams->as16ScaleFactor[s32Ch * s32NumOfSubBands + s32Sb] + - *ps16GenTabPtr); + if (s32Loudness > 0) { + *(ps16GenBufPtr) = (SINT16)(s32Loudness >> 1); + } else { + *(ps16GenBufPtr) = (SINT16)s32Loudness; + } + } + ps16GenBufPtr++; + ps16GenTabPtr++; + } + + } + + /* max bitneed index is searched*/ + s32MaxBitNeed = 0; + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) { + if ( *(ps16GenBufPtr) > s32MaxBitNeed) { + s32MaxBitNeed = *(ps16GenBufPtr); + } + + ps16GenBufPtr++; + } + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + /*iterative process to find hwo many bitslices fit into the bitpool*/ + s32BitSlice = s32MaxBitNeed + 1; + s32BitCount = pstrCodecParams->s16BitPool; + s32SliceCount = 0; + do { + s32BitSlice --; + s32BitCount -= s32SliceCount; + s32SliceCount = 0; + + for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) { + if ( (((*ps16GenBufPtr - s32BitSlice) < 16) && (*ps16GenBufPtr - s32BitSlice) >= 1)) { + if ((*ps16GenBufPtr - s32BitSlice) == 1) { + s32SliceCount += 2; + } else { + s32SliceCount++; + } + } + ps16GenBufPtr++; + + }/*end of for*/ + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + } while (s32BitCount - s32SliceCount > 0); + + if (s32BitCount == 0) { + s32BitCount -= s32SliceCount; + s32BitSlice --; + } + + /*Bits are distributed until the last bitslice is reached*/ + ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * s32NumOfSubBands; + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) { + if (*(ps16GenBufPtr) < s32BitSlice + 2) { + *(ps16GenArrPtr) = 0; + } else + *(ps16GenArrPtr) = ((*(ps16GenBufPtr) - s32BitSlice) < 16) ? + (SINT16)(*(ps16GenBufPtr) - s32BitSlice) : 16; + + ps16GenBufPtr++; + ps16GenArrPtr++; + } + ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * s32NumOfSubBands; + ps16GenBufPtr = ps16BitNeed + s32Ch * s32NumOfSubBands; + /*the remaining bits are allocated starting at subband 0*/ + s32Sb = 0; + while ( (s32BitCount > 0) && (s32Sb < s32NumOfSubBands) ) { + if ( (*(ps16GenArrPtr) >= 2) && (*(ps16GenArrPtr) < 16) ) { + (*(ps16GenArrPtr))++; + s32BitCount--; + } else if ( (*(ps16GenBufPtr) == s32BitSlice + 1) && + (s32BitCount > 1) ) { + *(ps16GenArrPtr) = 2; + s32BitCount -= 2; + } + s32Sb++; + ps16GenArrPtr++; + ps16GenBufPtr++; + } + ps16GenArrPtr = pstrCodecParams->as16Bits + s32Ch * s32NumOfSubBands; + + + s32Sb = 0; + while ( (s32BitCount > 0) && (s32Sb < s32NumOfSubBands) ) { + if ( *(ps16GenArrPtr) < 16) { + (*(ps16GenArrPtr))++; + s32BitCount--; + } + s32Sb++; + ps16GenArrPtr++; + } + } +} +/*End of BitAlloc() function*/ + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c new file mode 100644 index 0000000000..5363d3559a --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_bit_alloc_ste.c @@ -0,0 +1,192 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the code for bit allocation algorithm. It calculates + * the number of bits required for the encoded stream of data. + * + ******************************************************************************/ + +/*Includes*/ +#include "bt_target.h" +#include "sbc_encoder.h" +#include "sbc_enc_func_declare.h" + +#if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) + +/*global arrays*/ +extern const SINT16 sbc_enc_as16Offset4[4][4]; +extern const SINT16 sbc_enc_as16Offset8[4][8]; + +/**************************************************************************** +* BitAlloc - Calculates the required number of bits for the given scale factor +* and the number of subbands. +* +* RETURNS : N/A +*/ + +void sbc_enc_bit_alloc_ste(SBC_ENC_PARAMS *pstrCodecParams) +{ + /* CAUTIOM -> mips optim for arm 32 require to use SINT32 instead of SINT16 */ + /* Do not change variable type or name */ + SINT32 s32MaxBitNeed; /*to store the max bits needed per sb*/ + SINT32 s32BitCount; /*the used number of bits*/ + SINT32 s32SliceCount; /*to store hwo many slices can be put in bitpool*/ + SINT32 s32BitSlice; /*number of bitslices in bitpool*/ + SINT32 s32Sb; /*counter for sub-band*/ + SINT32 s32Ch; /*counter for channel*/ + SINT16 *ps16BitNeed; /*temp memory to store required number of bits*/ + SINT32 s32Loudness; /*used in Loudness calculation*/ + SINT16 *ps16GenBufPtr, *pas16ScaleFactor; + SINT16 *ps16GenArrPtr; + SINT16 *ps16GenTabPtr; + SINT32 s32NumOfSubBands = pstrCodecParams->s16NumOfSubBands; + SINT32 s32BitPool = pstrCodecParams->s16BitPool; + + /* bitneed values are derived from scale factor */ + if (pstrCodecParams->s16AllocationMethod == SBC_SNR) { + ps16BitNeed = pstrCodecParams->as16ScaleFactor; + s32MaxBitNeed = pstrCodecParams->s16MaxBitNeed; + } else { + ps16BitNeed = pstrCodecParams->s16ScartchMemForBitAlloc; + pas16ScaleFactor = pstrCodecParams->as16ScaleFactor; + s32MaxBitNeed = 0; + ps16GenBufPtr = ps16BitNeed; + for (s32Ch = 0; s32Ch < 2; s32Ch++) { + if (s32NumOfSubBands == 4) { + ps16GenTabPtr = (SINT16 *)sbc_enc_as16Offset4[pstrCodecParams->s16SamplingFreq]; + } else { + ps16GenTabPtr = (SINT16 *)sbc_enc_as16Offset8[pstrCodecParams->s16SamplingFreq]; + } + + for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) { + if (*pas16ScaleFactor == 0) { + *ps16GenBufPtr = -5; + } else { + s32Loudness = (SINT32)(*pas16ScaleFactor - *ps16GenTabPtr); + + if (s32Loudness > 0) { + *ps16GenBufPtr = (SINT16)(s32Loudness >> 1); + } else { + *ps16GenBufPtr = (SINT16)s32Loudness; + } + } + + if (*ps16GenBufPtr > s32MaxBitNeed) { + s32MaxBitNeed = *ps16GenBufPtr; + } + pas16ScaleFactor++; + ps16GenBufPtr++; + ps16GenTabPtr++; + } + } + } + + /* iterative process to find out hwo many bitslices fit into the bitpool */ + s32BitSlice = s32MaxBitNeed + 1; + s32BitCount = s32BitPool; + s32SliceCount = 0; + do { + s32BitSlice --; + s32BitCount -= s32SliceCount; + s32SliceCount = 0; + ps16GenBufPtr = ps16BitNeed; + + for (s32Sb = 0; s32Sb < 2 * s32NumOfSubBands; s32Sb++) { + if ( (*ps16GenBufPtr >= s32BitSlice + 1) && (*ps16GenBufPtr < s32BitSlice + 16) ) { + if (*(ps16GenBufPtr) == s32BitSlice + 1) { + s32SliceCount += 2; + } else { + s32SliceCount++; + } + } + ps16GenBufPtr++; + } + } while (s32BitCount - s32SliceCount > 0); + + if (s32BitCount - s32SliceCount == 0) { + s32BitCount -= s32SliceCount; + s32BitSlice --; + } + + /* Bits are distributed until the last bitslice is reached */ + ps16GenBufPtr = ps16BitNeed; + ps16GenArrPtr = pstrCodecParams->as16Bits; + for (s32Ch = 0; s32Ch < 2; s32Ch++) { + for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) { + if (*ps16GenBufPtr < s32BitSlice + 2) { + *ps16GenArrPtr = 0; + } else + *ps16GenArrPtr = ((*(ps16GenBufPtr) - s32BitSlice) < 16) ? + (SINT16)(*(ps16GenBufPtr) - s32BitSlice) : 16; + ps16GenBufPtr++; + ps16GenArrPtr++; + } + } + + /* the remaining bits are allocated starting at subband 0 */ + s32Ch = 0; + s32Sb = 0; + ps16GenBufPtr = ps16BitNeed; + ps16GenArrPtr -= 2 * s32NumOfSubBands; + + while ( (s32BitCount > 0) && (s32Sb < s32NumOfSubBands) ) { + if ( (*(ps16GenArrPtr) >= 2) && (*(ps16GenArrPtr) < 16) ) { + (*(ps16GenArrPtr))++; + s32BitCount--; + } else if ((*ps16GenBufPtr == s32BitSlice + 1) && (s32BitCount > 1)) { + *(ps16GenArrPtr) = 2; + s32BitCount -= 2; + } + if (s32Ch == 1) { + s32Ch = 0; + s32Sb++; + ps16GenBufPtr = ps16BitNeed + s32Sb; + ps16GenArrPtr = pstrCodecParams->as16Bits + s32Sb; + + } else { + s32Ch = 1; + ps16GenBufPtr = ps16BitNeed + s32NumOfSubBands + s32Sb; + ps16GenArrPtr = pstrCodecParams->as16Bits + s32NumOfSubBands + s32Sb; + } + } + + s32Ch = 0; + s32Sb = 0; + ps16GenArrPtr = pstrCodecParams->as16Bits; + + while ((s32BitCount > 0) && (s32Sb < s32NumOfSubBands)) { + if (*(ps16GenArrPtr) < 16) { + (*(ps16GenArrPtr))++; + s32BitCount--; + } + if (s32Ch == 1) { + s32Ch = 0; + s32Sb++; + ps16GenArrPtr = pstrCodecParams->as16Bits + s32Sb; + } else { + s32Ch = 1; + ps16GenArrPtr = pstrCodecParams->as16Bits + s32NumOfSubBands + s32Sb; + } + } +} + +/*End of BitAlloc() function*/ + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c new file mode 100644 index 0000000000..d1cfe74312 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_enc_coeffs.c @@ -0,0 +1,318 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains the Windowing coeffs for synthesis filter + * + ******************************************************************************/ +#include "bt_target.h" +#include "sbc_encoder.h" + +#if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) + +#if (SBC_ARM_ASM_OPT==FALSE && SBC_IPAQ_OPT==FALSE) +#if (SBC_IS_64_MULT_IN_WINDOW_ACCU == FALSE) +/*Window coeff for 4 sub band case*/ +const SINT16 gas32CoeffFor4SBs[] = { + (SINT16)((SINT32)0x00000000 >> 16), (SINT16)0x00000000, + (SINT16)((SINT32)0x001194E6 >> 16), (SINT16)0x001194E6, + (SINT16)((SINT32)0x0030E2D3 >> 16), (SINT16)0x0030E2D3, + (SINT16)((SINT32)0x00599403 >> 16), (SINT16)0x00599403, + (SINT16)((SINT32)0x007DBCC8 >> 16), (SINT16)0x007DBCC8, + (SINT16)((SINT32)0x007F88E4 >> 16), (SINT16)0x007F88E4, + (SINT16)((SINT32)0x003D239B >> 16), (SINT16)0x003D239B, + (SINT16)((SINT32)0xFF9BB9D5 >> 16), (SINT16)0xFF9BB9D5, + + (SINT16)((SINT32)0x01659F45 >> 16), (SINT16)0x01659F45, + (SINT16)((SINT32)0x029DBAA3 >> 16), (SINT16)0x029DBAA3, + (SINT16)((SINT32)0x03B23341 >> 16), (SINT16)0x03B23341, + (SINT16)((SINT32)0x041EEE40 >> 16), (SINT16)0x041EEE40, + (SINT16)((SINT32)0x034FEE2C >> 16), (SINT16)0x034FEE2C, + (SINT16)((SINT32)0x00C8F2BC >> 16), (SINT16)0x00C8F2BC, + (SINT16)((SINT32)0xFC4F91D4 >> 16), (SINT16)0xFC4F91D4, + (SINT16)((SINT32)0xF60FAF37 >> 16), (SINT16)0xF60FAF37, + + (SINT16)((SINT32)0x115B1ED2 >> 16), (SINT16)0x115B1ED2, + (SINT16)((SINT32)0x18F55C90 >> 16), (SINT16)0x18F55C90, + (SINT16)((SINT32)0x1F91CA46 >> 16), (SINT16)0x1F91CA46, + (SINT16)((SINT32)0x2412F251 >> 16), (SINT16)0x2412F251, + (SINT16)((SINT32)0x25AC1FF2 >> 16), (SINT16)0x25AC1FF2, + (SINT16)((SINT32)0x2412F251 >> 16), (SINT16)0x2412F251, + (SINT16)((SINT32)0x1F91CA46 >> 16), (SINT16)0x1F91CA46, + (SINT16)((SINT32)0x18F55C90 >> 16), (SINT16)0x18F55C90, + + (SINT16)((SINT32)0xEEA4E12E >> 16), (SINT16)0xEEA4E12E, + (SINT16)((SINT32)0xF60FAF37 >> 16), (SINT16)0xF60FAF37, + (SINT16)((SINT32)0xFC4F91D4 >> 16), (SINT16)0xFC4F91D4, + (SINT16)((SINT32)0x00C8F2BC >> 16), (SINT16)0x00C8F2BC, + (SINT16)((SINT32)0x034FEE2C >> 16), (SINT16)0x034FEE2C, + (SINT16)((SINT32)0x041EEE40 >> 16), (SINT16)0x041EEE40, + (SINT16)((SINT32)0x03B23341 >> 16), (SINT16)0x03B23341, + (SINT16)((SINT32)0x029DBAA3 >> 16), (SINT16)0x029DBAA3, + + (SINT16)((SINT32)0xFE9A60BB >> 16), (SINT16)0xFE9A60BB, + (SINT16)((SINT32)0xFF9BB9D5 >> 16), (SINT16)0xFF9BB9D5, + (SINT16)((SINT32)0x003D239B >> 16), (SINT16)0x003D239B, + (SINT16)((SINT32)0x007F88E4 >> 16), (SINT16)0x007F88E4, + (SINT16)((SINT32)0x007DBCC8 >> 16), (SINT16)0x007DBCC8, + (SINT16)((SINT32)0x00599403 >> 16), (SINT16)0x00599403, + (SINT16)((SINT32)0x0030E2D3 >> 16), (SINT16)0x0030E2D3, + (SINT16)((SINT32)0x001194E6 >> 16), (SINT16)0x001194E6 +}; + +/*Window coeff for 8 sub band case*/ +const SINT16 gas32CoeffFor8SBs[] = { + (SINT16)((SINT32)0x00000000 >> 16), (SINT16)0x00000000, + (SINT16)((SINT32)0x00052173 >> 16), (SINT16)0x00052173, + (SINT16)((SINT32)0x000B3F71 >> 16), (SINT16)0x000B3F71, + (SINT16)((SINT32)0x00122C7D >> 16), (SINT16)0x00122C7D, + (SINT16)((SINT32)0x001AFF89 >> 16), (SINT16)0x001AFF89, + (SINT16)((SINT32)0x00255A62 >> 16), (SINT16)0x00255A62, + (SINT16)((SINT32)0x003060F4 >> 16), (SINT16)0x003060F4, + (SINT16)((SINT32)0x003A72E7 >> 16), (SINT16)0x003A72E7, + + (SINT16)((SINT32)0x0041EC6A >> 16), (SINT16)0x0041EC6A, /* 8 */ + (SINT16)((SINT32)0x0044EF48 >> 16), (SINT16)0x0044EF48, + (SINT16)((SINT32)0x00415B75 >> 16), (SINT16)0x00415B75, + (SINT16)((SINT32)0x0034F8B6 >> 16), (SINT16)0x0034F8B6, + (SINT16)((SINT32)0x001D8FD2 >> 16), (SINT16)0x001D8FD2, + (SINT16)((SINT32)0xFFFA2413 >> 16), (SINT16)0xFFFA2413, + (SINT16)((SINT32)0xFFC9F10E >> 16), (SINT16)0xFFC9F10E, + (SINT16)((SINT32)0xFF8D6793 >> 16), (SINT16)0xFF8D6793, + + (SINT16)((SINT32)0x00B97348 >> 16), (SINT16)0x00B97348, /* 16 */ + (SINT16)((SINT32)0x01071B96 >> 16), (SINT16)0x01071B96, + (SINT16)((SINT32)0x0156B3CA >> 16), (SINT16)0x0156B3CA, + (SINT16)((SINT32)0x01A1B38B >> 16), (SINT16)0x01A1B38B, + (SINT16)((SINT32)0x01E0224C >> 16), (SINT16)0x01E0224C, + (SINT16)((SINT32)0x0209291F >> 16), (SINT16)0x0209291F, + (SINT16)((SINT32)0x02138653 >> 16), (SINT16)0x02138653, + (SINT16)((SINT32)0x01F5F424 >> 16), (SINT16)0x01F5F424, + + (SINT16)((SINT32)0x01A7ECEF >> 16), (SINT16)0x01A7ECEF, /* 24 */ + (SINT16)((SINT32)0x01223EBA >> 16), (SINT16)0x01223EBA, + (SINT16)((SINT32)0x005FD0FF >> 16), (SINT16)0x005FD0FF, + (SINT16)((SINT32)0xFF5EEB73 >> 16), (SINT16)0xFF5EEB73, + (SINT16)((SINT32)0xFE20435D >> 16), (SINT16)0xFE20435D, + (SINT16)((SINT32)0xFCA86E7E >> 16), (SINT16)0xFCA86E7E, + (SINT16)((SINT32)0xFAFF95FC >> 16), (SINT16)0xFAFF95FC, + (SINT16)((SINT32)0xF9312891 >> 16), (SINT16)0xF9312891, + + (SINT16)((SINT32)0x08B4307A >> 16), (SINT16)0x08B4307A, /* 32 */ + (SINT16)((SINT32)0x0A9F3E9A >> 16), (SINT16)0x0A9F3E9A, + (SINT16)((SINT32)0x0C7D59B6 >> 16), (SINT16)0x0C7D59B6, + (SINT16)((SINT32)0x0E3BB16F >> 16), (SINT16)0x0E3BB16F, + (SINT16)((SINT32)0x0FC721F9 >> 16), (SINT16)0x0FC721F9, + (SINT16)((SINT32)0x110ECEF0 >> 16), (SINT16)0x110ECEF0, + (SINT16)((SINT32)0x120435FA >> 16), (SINT16)0x120435FA, + (SINT16)((SINT32)0x129C226F >> 16), (SINT16)0x129C226F, + + (SINT16)((SINT32)0x12CF6C75 >> 16), (SINT16)0x12CF6C75, /* 40 */ + (SINT16)((SINT32)0x129C226F >> 16), (SINT16)0x129C226F, + (SINT16)((SINT32)0x120435FA >> 16), (SINT16)0x120435FA, + (SINT16)((SINT32)0x110ECEF0 >> 16), (SINT16)0x110ECEF0, + (SINT16)((SINT32)0x0FC721F9 >> 16), (SINT16)0x0FC721F9, + (SINT16)((SINT32)0x0E3BB16F >> 16), (SINT16)0x0E3BB16F, + (SINT16)((SINT32)0x0C7D59B6 >> 16), (SINT16)0x0C7D59B6, + (SINT16)((SINT32)0x0A9F3E9A >> 16), (SINT16)0x0A9F3E9A, + + (SINT16)((SINT32)0xF74BCF86 >> 16), (SINT16)0xF74BCF86, /* 48 */ + (SINT16)((SINT32)0xF9312891 >> 16), (SINT16)0xF9312891, + (SINT16)((SINT32)0xFAFF95FC >> 16), (SINT16)0xFAFF95FC, + (SINT16)((SINT32)0xFCA86E7E >> 16), (SINT16)0xFCA86E7E, + (SINT16)((SINT32)0xFE20435D >> 16), (SINT16)0xFE20435D, + (SINT16)((SINT32)0xFF5EEB73 >> 16), (SINT16)0xFF5EEB73, + (SINT16)((SINT32)0x005FD0FF >> 16), (SINT16)0x005FD0FF, + (SINT16)((SINT32)0x01223EBA >> 16), (SINT16)0x01223EBA, + + (SINT16)((SINT32)0x01A7ECEF >> 16), (SINT16)0x01A7ECEF, /* 56 */ + (SINT16)((SINT32)0x01F5F424 >> 16), (SINT16)0x01F5F424, + (SINT16)((SINT32)0x02138653 >> 16), (SINT16)0x02138653, + (SINT16)((SINT32)0x0209291F >> 16), (SINT16)0x0209291F, + (SINT16)((SINT32)0x01E0224C >> 16), (SINT16)0x01E0224C, + (SINT16)((SINT32)0x01A1B38B >> 16), (SINT16)0x01A1B38B, + (SINT16)((SINT32)0x0156B3CA >> 16), (SINT16)0x0156B3CA, + (SINT16)((SINT32)0x01071B96 >> 16), (SINT16)0x01071B96, + + (SINT16)((SINT32)0xFF468CB8 >> 16), (SINT16)0xFF468CB8, /* 64 */ + (SINT16)((SINT32)0xFF8D6793 >> 16), (SINT16)0xFF8D6793, + (SINT16)((SINT32)0xFFC9F10E >> 16), (SINT16)0xFFC9F10E, + (SINT16)((SINT32)0xFFFA2413 >> 16), (SINT16)0xFFFA2413, + (SINT16)((SINT32)0x001D8FD2 >> 16), (SINT16)0x001D8FD2, + (SINT16)((SINT32)0x0034F8B6 >> 16), (SINT16)0x0034F8B6, + (SINT16)((SINT32)0x00415B75 >> 16), (SINT16)0x00415B75, + (SINT16)((SINT32)0x0044EF48 >> 16), (SINT16)0x0044EF48, + + (SINT16)((SINT32)0x0041EC6A >> 16), (SINT16)0x0041EC6A, /* 72 */ + (SINT16)((SINT32)0x003A72E7 >> 16), (SINT16)0x003A72E7, + (SINT16)((SINT32)0x003060F4 >> 16), (SINT16)0x003060F4, + (SINT16)((SINT32)0x00255A62 >> 16), (SINT16)0x00255A62, + (SINT16)((SINT32)0x001AFF89 >> 16), (SINT16)0x001AFF89, + (SINT16)((SINT32)0x00122C7D >> 16), (SINT16)0x00122C7D, + (SINT16)((SINT32)0x000B3F71 >> 16), (SINT16)0x000B3F71, + (SINT16)((SINT32)0x00052173 >> 16), (SINT16)0x00052173 +}; + +#else + +/*Window coeff for 4 sub band case*/ +const SINT32 gas32CoeffFor4SBs[] = { + (SINT32)0x00000000, + (SINT32)0x001194E6, + (SINT32)0x0030E2D3, + (SINT32)0x00599403, + (SINT32)0x007DBCC8, + (SINT32)0x007F88E4, + (SINT32)0x003D239B, + (SINT32)0xFF9BB9D5, + + (SINT32)0x01659F45, + (SINT32)0x029DBAA3, + (SINT32)0x03B23341, + (SINT32)0x041EEE40, + (SINT32)0x034FEE2C, + (SINT32)0x00C8F2BC, + (SINT32)0xFC4F91D4, + (SINT32)0xF60FAF37, + + (SINT32)0x115B1ED2, + (SINT32)0x18F55C90, + (SINT32)0x1F91CA46, + (SINT32)0x2412F251, + (SINT32)0x25AC1FF2, + (SINT32)0x2412F251, + (SINT32)0x1F91CA46, + (SINT32)0x18F55C90, + + (SINT32)0xEEA4E12E, + (SINT32)0xF60FAF37, + (SINT32)0xFC4F91D4, + (SINT32)0x00C8F2BC, + (SINT32)0x034FEE2C, + (SINT32)0x041EEE40, + (SINT32)0x03B23341, + (SINT32)0x029DBAA3, + + (SINT32)0xFE9A60BB, + (SINT32)0xFF9BB9D5, + (SINT32)0x003D239B, + (SINT32)0x007F88E4, + (SINT32)0x007DBCC8, + (SINT32)0x00599403, + (SINT32)0x0030E2D3, + (SINT32)0x001194E6 +}; + +/*Window coeff for 8 sub band case*/ +const SINT32 gas32CoeffFor8SBs[] = { + (SINT32)0x00000000, + (SINT32)0x00052173, + (SINT32)0x000B3F71, + (SINT32)0x00122C7D, + (SINT32)0x001AFF89, + (SINT32)0x00255A62, + (SINT32)0x003060F4, + (SINT32)0x003A72E7, + + (SINT32)0x0041EC6A, /* 8 */ + (SINT32)0x0044EF48, + (SINT32)0x00415B75, + (SINT32)0x0034F8B6, + (SINT32)0x001D8FD2, + (SINT32)0xFFFA2413, + (SINT32)0xFFC9F10E, + (SINT32)0xFF8D6793, + + (SINT32)0x00B97348, /* 16 */ + (SINT32)0x01071B96, + (SINT32)0x0156B3CA, + (SINT32)0x01A1B38B, + (SINT32)0x01E0224C, + (SINT32)0x0209291F, + (SINT32)0x02138653, + (SINT32)0x01F5F424, + + (SINT32)0x01A7ECEF, /* 24 */ + (SINT32)0x01223EBA, + (SINT32)0x005FD0FF, + (SINT32)0xFF5EEB73, + (SINT32)0xFE20435D, + (SINT32)0xFCA86E7E, + (SINT32)0xFAFF95FC, + (SINT32)0xF9312891, + + (SINT32)0x08B4307A, /* 32 */ + (SINT32)0x0A9F3E9A, + (SINT32)0x0C7D59B6, + (SINT32)0x0E3BB16F, + (SINT32)0x0FC721F9, + (SINT32)0x110ECEF0, + (SINT32)0x120435FA, + (SINT32)0x129C226F, + + (SINT32)0x12CF6C75, /* 40 */ + (SINT32)0x129C226F, + (SINT32)0x120435FA, + (SINT32)0x110ECEF0, + (SINT32)0x0FC721F9, + (SINT32)0x0E3BB16F, + (SINT32)0x0C7D59B6, + (SINT32)0x0A9F3E9A, + + (SINT32)0xF74BCF86, /* 48 */ + (SINT32)0xF9312891, + (SINT32)0xFAFF95FC, + (SINT32)0xFCA86E7E, + (SINT32)0xFE20435D, + (SINT32)0xFF5EEB73, + (SINT32)0x005FD0FF, + (SINT32)0x01223EBA, + + (SINT32)0x01A7ECEF, /* 56 */ + (SINT32)0x01F5F424, + (SINT32)0x02138653, + (SINT32)0x0209291F, + (SINT32)0x01E0224C, + (SINT32)0x01A1B38B, + (SINT32)0x0156B3CA, + (SINT32)0x01071B96, + + (SINT32)0xFF468CB8, /* 64 */ + (SINT32)0xFF8D6793, + (SINT32)0xFFC9F10E, + (SINT32)0xFFFA2413, + (SINT32)0x001D8FD2, + (SINT32)0x0034F8B6, + (SINT32)0x00415B75, + (SINT32)0x0044EF48, + + (SINT32)0x0041EC6A, /* 72 */ + (SINT32)0x003A72E7, + (SINT32)0x003060F4, + (SINT32)0x00255A62, + (SINT32)0x001AFF89, + (SINT32)0x00122C7D, + (SINT32)0x000B3F71, + (SINT32)0x00052173 +}; + +#endif +#endif + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_encoder.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_encoder.c new file mode 100644 index 0000000000..748f85f6f2 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_encoder.c @@ -0,0 +1,403 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * contains code for encoder flow and initalization of encoder + * + ******************************************************************************/ + +#include +#include "bt_target.h" +#include "sbc_encoder.h" +#include "sbc_enc_func_declare.h" + +#if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) + +SINT16 EncMaxShiftCounter; + +/************************************************************************************************* + * SBC encoder scramble code + * Purpose: to tie the SBC code with BTE/mobile stack code, + * especially for the case when the SBC is ported into a third-party Multimedia chip + * + * Algorithm: + * init process: all counters reset to 0, + * calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2) + * scramble side: the init process happens every time SBC_Encoder_Init() is called. + * descramble side: it would be nice to know if he "init" process has happened. + * alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100). + * + * scramble process: + * The CRC byte: + * Every SBC frame has a frame header. + * The 1st byte is the sync word and the following 2 bytes are about the stream format. + * They are supposed to be "constant" within a "song" + * The 4th byte is the CRC byte. The CRC byte is bound to be random. + * Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index". + * + * SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame. + * + * The "use" bit is any bit in SBC_PRTC_USE_MASK is set. + * If set, SBC uses the "index" from the current frame. + * If not set, SBC uses the "index" from the previous frame or 0. + * + * index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index + * + * if(index > 0) + * { + * p = &u8frame[base_index]; + * if((index&1)&&(u16PacketLength > (base_index+index*2))) + * { + * // odd index: swap 2 bytes + * tmp = p[index]; + * p[index] = p[index*2]; + * p[index*2] = tmp; + * } + * else + * { + * // even index: shift by 3 + * tmp = (p[index] >> 5) + (p[index] << 3); + * p[index] = tmp; + * } + * } + * //else index is 0. The frame stays unaltered + * + */ + +#define SBC_PRTC_CRC_IDX 3 +#define SBC_PRTC_USE_MASK 0x64 +#define SBC_PRTC_SYNC_MASK 0x10 +#define SBC_PRTC_CIDX 0 +#define SBC_PRTC_LIDX 1 +typedef struct { + UINT8 use; + UINT8 idx; +} tSBC_FR_CB; + +typedef struct { + tSBC_FR_CB fr[2]; + UINT8 init; + UINT8 index; + UINT8 base; +} tSBC_PRTC_CB; +tSBC_PRTC_CB sbc_prtc_cb; + +#define SBC_PRTC_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2)) +#define SBC_PRTC_CHK_INIT(ar) {if(sbc_prtc_cb.init == 0){sbc_prtc_cb.init=1; ar[0] &= ~SBC_PRTC_SYNC_MASK;}} +#define SBC_PRTC_C2L() {p_last=&sbc_prtc_cb.fr[SBC_PRTC_LIDX]; p_cur=&sbc_prtc_cb.fr[SBC_PRTC_CIDX]; \ + p_last->idx = p_cur->idx; p_last->use = p_cur->use;} +#define SBC_PRTC_GETC(ar) {p_cur->use = ar[SBC_PRTC_CRC_IDX] & SBC_PRTC_USE_MASK; \ + p_cur->idx = SBC_PRTC_IDX(ar[SBC_PRTC_CRC_IDX]);} +#define SBC_PRTC_CHK_CRC(ar) {SBC_PRTC_C2L();SBC_PRTC_GETC(ar);sbc_prtc_cb.index = (p_cur->use)?SBC_PRTC_CIDX:SBC_PRTC_LIDX;} +#define SBC_PRTC_SCRMB(ar) {idx = sbc_prtc_cb.fr[sbc_prtc_cb.index].idx; \ + if(idx > 0){if((idx&1)&&(pstrEncParams->u16PacketLength > (sbc_prtc_cb.base+(idx<<1)))) {tmp2=idx<<1; tmp=ar[idx];ar[idx]=ar[tmp2];ar[tmp2]=tmp;} \ + else{tmp2=ar[idx]; tmp=(tmp2>>5)+(tmp2<<3);ar[idx]=(UINT8)tmp;}}} + +#if (SBC_JOINT_STE_INCLUDED == TRUE) +SINT32 s32LRDiff[SBC_MAX_NUM_OF_BLOCKS] = {0}; +SINT32 s32LRSum[SBC_MAX_NUM_OF_BLOCKS] = {0}; +#endif + +void SBC_Encoder(SBC_ENC_PARAMS *pstrEncParams) +{ + SINT32 s32Ch; /* counter for ch*/ + SINT32 s32Sb; /* counter for sub-band*/ + UINT32 u32Count, maxBit = 0; /* loop count*/ + SINT32 s32MaxValue; /* temp variable to store max value */ + + SINT16 *ps16ScfL; + SINT32 *SbBuffer; + SINT32 s32Blk; /* counter for block*/ + SINT32 s32NumOfBlocks = pstrEncParams->s16NumOfBlocks; +#if (SBC_JOINT_STE_INCLUDED == TRUE) + SINT32 s32MaxValue2; + UINT32 u32CountSum, u32CountDiff; + SINT32 *pSum, *pDiff; +#endif + UINT8 *pu8; + tSBC_FR_CB *p_cur, *p_last; + UINT32 idx, tmp, tmp2; + register SINT32 s32NumOfSubBands = pstrEncParams->s16NumOfSubBands; + + pstrEncParams->pu8NextPacket = pstrEncParams->pu8Packet; + +#if (SBC_NO_PCM_CPY_OPTION == TRUE) + pstrEncParams->ps16NextPcmBuffer = pstrEncParams->ps16PcmBuffer; +#else + pstrEncParams->ps16NextPcmBuffer = pstrEncParams->as16PcmBuffer; +#endif + do { + /* SBC ananlysis filter*/ + if (s32NumOfSubBands == 4) { + SbcAnalysisFilter4(pstrEncParams); + } else { + SbcAnalysisFilter8(pstrEncParams); + } + + /* compute the scale factor, and save the max */ + ps16ScfL = pstrEncParams->as16ScaleFactor; + s32Ch = pstrEncParams->s16NumOfChannels * s32NumOfSubBands; + + pstrEncParams->ps16NextPcmBuffer += s32Ch * s32NumOfBlocks; /* in case of multible sbc frame to encode update the pcm pointer */ + + for (s32Sb = 0; s32Sb < s32Ch; s32Sb++) { + SbBuffer = pstrEncParams->s32SbBuffer + s32Sb; + s32MaxValue = 0; + for (s32Blk = s32NumOfBlocks; s32Blk > 0; s32Blk--) { + if (s32MaxValue < abs32(*SbBuffer)) { + s32MaxValue = abs32(*SbBuffer); + } + SbBuffer += s32Ch; + } + + u32Count = (s32MaxValue > 0x800000) ? 9 : 0; + + for ( ; u32Count < 15; u32Count++) { + if (s32MaxValue <= (SINT32)(0x8000 << u32Count)) { + break; + } + } + *ps16ScfL++ = (SINT16)u32Count; + + if (u32Count > maxBit) { + maxBit = u32Count; + } + } + /* In case of JS processing,check whether to use JS */ +#if (SBC_JOINT_STE_INCLUDED == TRUE) + if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) { + /* Calculate sum and differance scale factors for making JS decision */ + ps16ScfL = pstrEncParams->as16ScaleFactor ; + /* calculate the scale factor of Joint stereo max sum and diff */ + for (s32Sb = 0; s32Sb < s32NumOfSubBands - 1; s32Sb++) { + SbBuffer = pstrEncParams->s32SbBuffer + s32Sb; + s32MaxValue2 = 0; + s32MaxValue = 0; + pSum = s32LRSum; + pDiff = s32LRDiff; + for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) { + *pSum = (*SbBuffer + * (SbBuffer + s32NumOfSubBands)) >> 1; + if (abs32(*pSum) > s32MaxValue) { + s32MaxValue = abs32(*pSum); + } + pSum++; + *pDiff = (*SbBuffer - * (SbBuffer + s32NumOfSubBands)) >> 1; + if (abs32(*pDiff) > s32MaxValue2) { + s32MaxValue2 = abs32(*pDiff); + } + pDiff++; + SbBuffer += s32Ch; + } + u32Count = (s32MaxValue > 0x800000) ? 9 : 0; + for ( ; u32Count < 15; u32Count++) { + if (s32MaxValue <= (SINT32)(0x8000 << u32Count)) { + break; + } + } + u32CountSum = u32Count; + u32Count = (s32MaxValue2 > 0x800000) ? 9 : 0; + for ( ; u32Count < 15; u32Count++) { + if (s32MaxValue2 <= (SINT32)(0x8000 << u32Count)) { + break; + } + } + u32CountDiff = u32Count; + if ( (*ps16ScfL + * (ps16ScfL + s32NumOfSubBands)) > (SINT16)(u32CountSum + u32CountDiff) ) { + + if (u32CountSum > maxBit) { + maxBit = u32CountSum; + } + + if (u32CountDiff > maxBit) { + maxBit = u32CountDiff; + } + + *ps16ScfL = (SINT16)u32CountSum; + *(ps16ScfL + s32NumOfSubBands) = (SINT16)u32CountDiff; + + SbBuffer = pstrEncParams->s32SbBuffer + s32Sb; + pSum = s32LRSum; + pDiff = s32LRDiff; + + for (s32Blk = 0; s32Blk < s32NumOfBlocks; s32Blk++) { + *SbBuffer = *pSum; + *(SbBuffer + s32NumOfSubBands) = *pDiff; + + SbBuffer += s32NumOfSubBands << 1; + pSum++; + pDiff++; + } + + pstrEncParams->as16Join[s32Sb] = 1; + } else { + pstrEncParams->as16Join[s32Sb] = 0; + } + ps16ScfL++; + } + pstrEncParams->as16Join[s32Sb] = 0; + } +#endif + + pstrEncParams->s16MaxBitNeed = (SINT16)maxBit; + + /* bit allocation */ + if ((pstrEncParams->s16ChannelMode == SBC_STEREO) || (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO)) { + sbc_enc_bit_alloc_ste(pstrEncParams); + } else { + sbc_enc_bit_alloc_mono(pstrEncParams); + } + + /* save the beginning of the frame. pu8NextPacket is modified in EncPacking() */ + pu8 = pstrEncParams->pu8NextPacket; + /* Quantize the encoded audio */ + EncPacking(pstrEncParams); + + /* scramble the code */ + SBC_PRTC_CHK_INIT(pu8); + SBC_PRTC_CHK_CRC(pu8); +#if 0 + if (pstrEncParams->u16PacketLength > ((sbc_prtc_cb.fr[sbc_prtc_cb.index].idx * 2) + sbc_prtc_cb.base)) { + printf("len: %d, idx: %d\n", pstrEncParams->u16PacketLength, sbc_prtc_cb.fr[sbc_prtc_cb.index].idx); + } else { + printf("len: %d, idx: %d!!!!\n", pstrEncParams->u16PacketLength, sbc_prtc_cb.fr[sbc_prtc_cb.index].idx); + } +#endif + SBC_PRTC_SCRMB((&pu8[sbc_prtc_cb.base])); + } while (--(pstrEncParams->u8NumPacketToEncode)); + + pstrEncParams->u8NumPacketToEncode = 1; /* default is one for retrocompatibility purpose */ + +} + +/**************************************************************************** +* InitSbcAnalysisFilt - Initalizes the input data to 0 +* +* RETURNS : N/A +*/ +void SBC_Encoder_Init(SBC_ENC_PARAMS *pstrEncParams) +{ + UINT16 s16SamplingFreq; /*temp variable to store smpling freq*/ + SINT16 s16Bitpool; /*to store bit pool value*/ + SINT16 s16BitRate; /*to store bitrate*/ + SINT16 s16FrameLen; /*to store frame length*/ + UINT16 HeaderParams; + + pstrEncParams->u8NumPacketToEncode = 1; /* default is one for retrocompatibility purpose */ + + /* Required number of channels */ + if (pstrEncParams->s16ChannelMode == SBC_MONO) { + pstrEncParams->s16NumOfChannels = 1; + } else { + pstrEncParams->s16NumOfChannels = 2; + } + + /* Bit pool calculation */ + if (pstrEncParams->s16SamplingFreq == SBC_sf16000) { + s16SamplingFreq = 16000; + } else if (pstrEncParams->s16SamplingFreq == SBC_sf32000) { + s16SamplingFreq = 32000; + } else if (pstrEncParams->s16SamplingFreq == SBC_sf44100) { + s16SamplingFreq = 44100; + } else { + s16SamplingFreq = 48000; + } + + if ( (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) + || (pstrEncParams->s16ChannelMode == SBC_STEREO) ) { + s16Bitpool = (SINT16)( (pstrEncParams->u16BitRate * + pstrEncParams->s16NumOfSubBands * 1000 / s16SamplingFreq) + - ( (32 + (4 * pstrEncParams->s16NumOfSubBands * + pstrEncParams->s16NumOfChannels) + + ( (pstrEncParams->s16ChannelMode - 2) * + pstrEncParams->s16NumOfSubBands ) ) + / pstrEncParams->s16NumOfBlocks) ); + + s16FrameLen = 4 + (4 * pstrEncParams->s16NumOfSubBands * + pstrEncParams->s16NumOfChannels) / 8 + + ( ((pstrEncParams->s16ChannelMode - 2) * + pstrEncParams->s16NumOfSubBands) + + (pstrEncParams->s16NumOfBlocks * s16Bitpool) ) / 8; + + s16BitRate = (8 * s16FrameLen * s16SamplingFreq) + / (pstrEncParams->s16NumOfSubBands * + pstrEncParams->s16NumOfBlocks * 1000); + + if (s16BitRate > pstrEncParams->u16BitRate) { + s16Bitpool--; + } + + if (pstrEncParams->s16NumOfSubBands == 8) { + pstrEncParams->s16BitPool = (s16Bitpool > 255) ? 255 : s16Bitpool; + } else { + pstrEncParams->s16BitPool = (s16Bitpool > 128) ? 128 : s16Bitpool; + } + } else { + s16Bitpool = (SINT16)( ((pstrEncParams->s16NumOfSubBands * + pstrEncParams->u16BitRate * 1000) + / (s16SamplingFreq * pstrEncParams->s16NumOfChannels)) + - ( ( (32 / pstrEncParams->s16NumOfChannels) + + (4 * pstrEncParams->s16NumOfSubBands) ) + / pstrEncParams->s16NumOfBlocks ) ); + + pstrEncParams->s16BitPool = (s16Bitpool > + (16 * pstrEncParams->s16NumOfSubBands)) + ? (16 * pstrEncParams->s16NumOfSubBands) : s16Bitpool; + } + + if (pstrEncParams->s16BitPool < 0) { + pstrEncParams->s16BitPool = 0; + } + /* sampling freq */ + HeaderParams = ((pstrEncParams->s16SamplingFreq & 3) << 6); + + /* number of blocks*/ + HeaderParams |= (((pstrEncParams->s16NumOfBlocks - 4) & 12) << 2); + + /* channel mode: mono, dual...*/ + HeaderParams |= ((pstrEncParams->s16ChannelMode & 3) << 2); + + /* Loudness or SNR */ + HeaderParams |= ((pstrEncParams->s16AllocationMethod & 1) << 1); + HeaderParams |= ((pstrEncParams->s16NumOfSubBands >> 3) & 1); /*4 or 8*/ + pstrEncParams->FrameHeader = HeaderParams; + + if (pstrEncParams->s16NumOfSubBands == 4) { + if (pstrEncParams->s16NumOfChannels == 1) { + EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 4 * 10) >> 2) << 2; + } else { + EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 4 * 10 * 2) >> 3) << 2; + } + } else { + if (pstrEncParams->s16NumOfChannels == 1) { + EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 8 * 10) >> 3) << 3; + } else { + EncMaxShiftCounter = ((ENC_VX_BUFFER_SIZE - 8 * 10 * 2) >> 4) << 3; + } + } + + APPL_TRACE_EVENT("SBC_Encoder_Init : bitrate %d, bitpool %d", + pstrEncParams->u16BitRate, pstrEncParams->s16BitPool); + + SbcAnalysisInit(); + + memset(&sbc_prtc_cb, 0, sizeof(tSBC_PRTC_CB)); + sbc_prtc_cb.base = 6 + pstrEncParams->s16NumOfChannels * pstrEncParams->s16NumOfSubBands / 2; +} + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/external/sbc/encoder/srce/sbc_packing.c b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_packing.c new file mode 100644 index 0000000000..47d7a6b965 --- /dev/null +++ b/components/bt/bluedroid/external/sbc/encoder/srce/sbc_packing.c @@ -0,0 +1,256 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains code for packing the Encoded data into bit streams. + * + ******************************************************************************/ +#include "bt_target.h" +#include "sbc_encoder.h" +#include "sbc_enc_func_declare.h" + +#if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) + +#if (SBC_ARM_ASM_OPT==TRUE) +#define Mult32(s32In1,s32In2,s32OutLow) \ +{ \ + __asm \ + { \ + MUL s32OutLow,s32In1,s32In2; \ + } \ +} +#define Mult64(s32In1, s32In2, s32OutLow, s32OutHi) \ +{ \ + __asm \ + { \ + SMULL s32OutLow,s32OutHi,s32In1,s32In2 \ + } \ +} +#else +#define Mult32(s32In1,s32In2,s32OutLow) s32OutLow=(SINT32)s32In1*(SINT32)s32In2; +#define Mult64(s32In1, s32In2, s32OutLow, s32OutHi) \ +{ \ + s32OutLow = ((SINT32)(UINT16)s32In1 * (UINT16)s32In2); \ + s32TempVal2 = (SINT32)((s32In1 >> 16) * (UINT16)s32In2); \ + s32Carry = ( (((UINT32)(s32OutLow)>>16)&0xFFFF) + \ + + (s32TempVal2 & 0xFFFF) ) >> 16; \ + s32OutLow += (s32TempVal2 << 16); \ + s32OutHi = (s32TempVal2 >> 16) + s32Carry; \ +} +#endif + +void EncPacking(SBC_ENC_PARAMS *pstrEncParams) +{ + UINT8 *pu8PacketPtr; /* packet ptr*/ + UINT8 Temp; + SINT32 s32Blk; /* counter for block*/ + SINT32 s32Ch; /* counter for channel*/ + SINT32 s32Sb; /* counter for sub-band*/ + SINT32 s32PresentBit; /* represents bit to be stored*/ + /*SINT32 s32LoopCountI; loop counter*/ + SINT32 s32LoopCountJ; /* loop counter*/ + UINT32 u32QuantizedSbValue, u32QuantizedSbValue0; /* temp variable to store quantized sb val*/ + SINT32 s32LoopCount; /* loop counter*/ + UINT8 u8XoredVal; /* to store XORed value in CRC calculation*/ + UINT8 u8CRC; /* to store CRC value*/ + SINT16 *ps16GenPtr; + SINT32 s32NumOfBlocks; + SINT32 s32NumOfSubBands = pstrEncParams->s16NumOfSubBands; + SINT32 s32NumOfChannels = pstrEncParams->s16NumOfChannels; + UINT32 u32SfRaisedToPow2; /*scale factor raised to power 2*/ + SINT16 *ps16ScfPtr; + SINT32 *ps32SbPtr; + UINT16 u16Levels; /*to store levels*/ + SINT32 s32Temp1; /*used in 64-bit multiplication*/ + SINT32 s32Low; /*used in 64-bit multiplication*/ +#if (SBC_IS_64_MULT_IN_QUANTIZER==TRUE) + SINT32 s32Hi1, s32Low1, s32Carry, s32TempVal2, s32Hi, s32Temp2; +#endif + + pu8PacketPtr = pstrEncParams->pu8NextPacket; /*Initialize the ptr*/ + *pu8PacketPtr++ = (UINT8)0x9C; /*Sync word*/ + *pu8PacketPtr++ = (UINT8)(pstrEncParams->FrameHeader); + + *pu8PacketPtr = (UINT8)(pstrEncParams->s16BitPool & 0x00FF); + pu8PacketPtr += 2; /*skip for CRC*/ + + /*here it indicate if it is byte boundary or nibble boundary*/ + s32PresentBit = 8; + Temp = 0; +#if (SBC_JOINT_STE_INCLUDED == TRUE) + if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) { + /* pack join stero parameters */ + for (s32Sb = 0; s32Sb < s32NumOfSubBands; s32Sb++) { + Temp <<= 1; + Temp |= pstrEncParams->as16Join[s32Sb]; + } + + /* pack RFA */ + if (s32NumOfSubBands == SUB_BANDS_4) { + s32PresentBit = 4; + } else { + *(pu8PacketPtr++) = Temp; + Temp = 0; + } + } +#endif + + /* Pack Scale factor */ + ps16GenPtr = pstrEncParams->as16ScaleFactor; + s32Sb = s32NumOfChannels * s32NumOfSubBands; + /*Temp=*pu8PacketPtr;*/ + for (s32Ch = s32Sb; s32Ch > 0; s32Ch--) { + Temp <<= 4; + Temp |= *ps16GenPtr++; + + if (s32PresentBit == 4) { + s32PresentBit = 8; + *(pu8PacketPtr++) = Temp; + Temp = 0; + } else { + s32PresentBit = 4; + } + } + + /* Pack samples */ + ps32SbPtr = pstrEncParams->s32SbBuffer; + /*Temp=*pu8PacketPtr;*/ + s32NumOfBlocks = pstrEncParams->s16NumOfBlocks; + for (s32Blk = s32NumOfBlocks - 1; s32Blk >= 0; s32Blk--) { + ps16GenPtr = pstrEncParams->as16Bits; + ps16ScfPtr = pstrEncParams->as16ScaleFactor; + for (s32Ch = s32Sb - 1; s32Ch >= 0; s32Ch--) { + s32LoopCount = *ps16GenPtr++; + if (s32LoopCount != 0) { +#if (SBC_IS_64_MULT_IN_QUANTIZER==TRUE) + /* finding level from reconstruction part of decoder */ + u32SfRaisedToPow2 = ((UINT32)1 << ((*ps16ScfPtr) + 1)); + u16Levels = (UINT16)(((UINT32)1 << s32LoopCount) - 1); + + /* quantizer */ + s32Temp1 = (*ps32SbPtr >> 2) + (u32SfRaisedToPow2 << 12); + s32Temp2 = u16Levels; + + Mult64 (s32Temp1, s32Temp2, s32Low, s32Hi); + + s32Low1 = s32Low >> ((*ps16ScfPtr) + 2); + s32Low1 &= ((UINT32)1 << (32 - ((*ps16ScfPtr) + 2))) - 1; + s32Hi1 = s32Hi << (32 - ((*ps16ScfPtr) + 2)); + + u32QuantizedSbValue0 = (UINT16)((s32Low1 | s32Hi1) >> 12); +#else + /* finding level from reconstruction part of decoder */ + u32SfRaisedToPow2 = ((UINT32)1 << *ps16ScfPtr); + u16Levels = (UINT16)(((UINT32)1 << s32LoopCount) - 1); + + /* quantizer */ + s32Temp1 = (*ps32SbPtr >> 15) + u32SfRaisedToPow2; + Mult32(s32Temp1, u16Levels, s32Low); + s32Low >>= (*ps16ScfPtr + 1); + u32QuantizedSbValue0 = (UINT16)s32Low; +#endif + /*store the number of bits required and the quantized s32Sb + sample to ease the coding*/ + u32QuantizedSbValue = u32QuantizedSbValue0; + + if (s32PresentBit >= s32LoopCount) { + Temp <<= s32LoopCount; + Temp |= u32QuantizedSbValue; + s32PresentBit -= s32LoopCount; + } else { + while (s32PresentBit < s32LoopCount) { + s32LoopCount -= s32PresentBit; + u32QuantizedSbValue >>= s32LoopCount; + + /*remove the unwanted msbs*/ + /*u32QuantizedSbValue <<= 16 - s32PresentBit; + u32QuantizedSbValue >>= 16 - s32PresentBit;*/ + + Temp <<= s32PresentBit; + + Temp |= u32QuantizedSbValue ; + /*restore the original*/ + u32QuantizedSbValue = u32QuantizedSbValue0; + + *(pu8PacketPtr++) = Temp; + Temp = 0; + s32PresentBit = 8; + } + Temp <<= s32LoopCount; + + /* remove the unwanted msbs */ + /*u32QuantizedSbValue <<= 16 - s32LoopCount; + u32QuantizedSbValue >>= 16 - s32LoopCount;*/ + + Temp |= u32QuantizedSbValue; + + s32PresentBit -= s32LoopCount; + } + } + ps16ScfPtr++; + ps32SbPtr++; + } + } + + Temp <<= s32PresentBit; + *pu8PacketPtr = Temp; + pstrEncParams->u16PacketLength = pu8PacketPtr - pstrEncParams->pu8NextPacket + 1; + /*find CRC*/ + pu8PacketPtr = pstrEncParams->pu8NextPacket + 1; /*Initialize the ptr*/ + u8CRC = 0x0F; + s32LoopCount = s32Sb >> 1; + + /* + The loops is run from the start of the packet till the scale factor + parameters. In case of JS, 'join' parameter is included in the packet + so that many more bytes are included in CRC calculation. + */ + Temp = *pu8PacketPtr; + for (s32Ch = 1; s32Ch < (s32LoopCount + 4); s32Ch++) { + /* skip sync word and CRC bytes */ + if (s32Ch != 3) { + for (s32LoopCountJ = 7; s32LoopCountJ >= 0; s32LoopCountJ--) { + u8XoredVal = ((u8CRC >> 7) & 0x01) ^ ((Temp >> s32LoopCountJ) & 0x01); + u8CRC <<= 1; + u8CRC ^= (u8XoredVal * 0x1D); + u8CRC &= 0xFF; + } + } + Temp = *(++pu8PacketPtr); + } + + if (pstrEncParams->s16ChannelMode == SBC_JOINT_STEREO) { + for (s32LoopCountJ = 7; s32LoopCountJ >= (8 - s32NumOfSubBands); s32LoopCountJ--) { + u8XoredVal = ((u8CRC >> 7) & 0x01) ^ ((Temp >> s32LoopCountJ) & 0x01); + u8CRC <<= 1; + u8CRC ^= (u8XoredVal * 0x1D); + u8CRC &= 0xFF; + } + } + + /* CRC calculation ends here */ + + /* store CRC in packet */ + pu8PacketPtr = pstrEncParams->pu8NextPacket; /*Initialize the ptr*/ + pu8PacketPtr += 3; + *pu8PacketPtr = u8CRC; + pstrEncParams->pu8NextPacket += pstrEncParams->u16PacketLength; /* move the pointer to the end in case there is more than one frame to encode */ +} + +#endif /* #if (defined(SBC_ENC_INCLUDED) && SBC_ENC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/gki/gki_buffer.c b/components/bt/bluedroid/gki/gki_buffer.c index 201df90e7f..9ce9a12149 100644 --- a/components/bt/bluedroid/gki/gki_buffer.c +++ b/components/bt/bluedroid/gki/gki_buffer.c @@ -181,12 +181,16 @@ void GKI_init_q (BUFFER_Q *p_q) void *GKI_getbuf_func(UINT16 size) { BUFFER_HDR_T *header = osi_malloc(size + BUFFER_HDR_SIZE); - header->status = BUF_STATUS_UNLINKED; - header->p_next = NULL; - header->Type = 0; - header->size = size; + if (header != NULL) { + header->status = BUF_STATUS_UNLINKED; + header->p_next = NULL; + header->Type = 0; + header->size = size; - return header + 1; + return header + 1; + } else { + return NULL; + } } /******************************************************************************* diff --git a/components/bt/bluedroid/hci/hci_hal_h4.c b/components/bt/bluedroid/hci/hci_hal_h4.c index e621450423..f26365e3ac 100644 --- a/components/bt/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/bluedroid/hci/hci_hal_h4.c @@ -217,11 +217,8 @@ static void hci_hal_h4_hdl_rx_packet(BT_HDR *packet) return; } if (type == DATA_TYPE_ACL) { - packet->offset--; stream += hdr_size - 2; STREAM_TO_UINT16(length, stream); - stream = packet->data + 1; - memcpy(packet->data, stream, packet->len); } else { stream += hdr_size - 1; STREAM_TO_UINT8(length, stream); diff --git a/components/bt/bluedroid/hci/include/buffer_allocator.h b/components/bt/bluedroid/hci/include/buffer_allocator.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/hci/include/hci_internals.h b/components/bt/bluedroid/hci/include/hci_internals.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/hci/packet_fragmenter.c b/components/bt/bluedroid/hci/packet_fragmenter.c index 9294cb5bbb..ce4642fe78 100644 --- a/components/bt/bluedroid/hci/packet_fragmenter.c +++ b/components/bt/bluedroid/hci/packet_fragmenter.c @@ -41,7 +41,6 @@ // TODO(zachoverflow): find good value for this #define NUMBER_OF_BUCKETS 42 -uint16_t data_len = 0; // Our interface and callbacks static const packet_fragmenter_t interface; @@ -129,7 +128,7 @@ static void reassemble_and_dispatch(BT_HDR *packet) LOG_DEBUG("reassemble_and_dispatch\n"); if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) { - uint8_t *stream = packet->data; + uint8_t *stream = packet->data + packet->offset; uint16_t handle; uint16_t l2cap_length; uint16_t acl_length; @@ -147,13 +146,9 @@ static void reassemble_and_dispatch(BT_HDR *packet) if (boundary_flag == START_PACKET_BOUNDARY) { if (partial_packet) { - LOG_DEBUG("%s found unfinished packet for handle with start packet. Dropping old.\n", __func__); - LOG_DEBUG("partial_packet->len = %x, offset = %x\n", partial_packet->len, partial_packet->len); - - + LOG_WARN("%s found unfinished packet for handle with start packet. Dropping old.\n", __func__); hash_map_erase(partial_packets, (void *)(uintptr_t)handle); - - + buffer_allocator->free(partial_packet); } uint16_t full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE; @@ -171,7 +166,7 @@ static void reassemble_and_dispatch(BT_HDR *packet) partial_packet->len = full_length; partial_packet->offset = packet->len; - memcpy(partial_packet->data, packet->data, packet->len); + memcpy(partial_packet->data, packet->data + packet->offset, packet->len); // Update the ACL data size to indicate the full expected length stream = partial_packet->data; @@ -188,8 +183,9 @@ static void reassemble_and_dispatch(BT_HDR *packet) return; } - packet->offset = HCI_ACL_PREAMBLE_SIZE; - uint16_t projected_offset = partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE); + packet->offset += HCI_ACL_PREAMBLE_SIZE; // skip ACL preamble + packet->len -= HCI_ACL_PREAMBLE_SIZE; + uint16_t projected_offset = partial_packet->offset + packet->len; if (projected_offset > partial_packet->len) { // len stores the expected length LOG_ERROR("%s got packet which would exceed expected length of %d. Truncating.\n", __func__, partial_packet->len); packet->len = partial_packet->len - partial_packet->offset; @@ -199,7 +195,7 @@ static void reassemble_and_dispatch(BT_HDR *packet) memcpy( partial_packet->data + partial_packet->offset, packet->data + packet->offset, - packet->len - packet->offset + packet->len ); // Free the old packet buffer, since we don't need it anymore @@ -207,15 +203,8 @@ static void reassemble_and_dispatch(BT_HDR *packet) partial_packet->offset = projected_offset; if (partial_packet->offset == partial_packet->len) { - stream = partial_packet->data; - STREAM_TO_UINT16(handle, stream); - STREAM_TO_UINT16(acl_length, stream); - STREAM_TO_UINT16(l2cap_length, stream); - LOG_DEBUG("partial_packet->offset = %x\n", partial_packet->offset); hash_map_erase(partial_packets, (void *)(uintptr_t)handle); partial_packet->offset = 0; - - callbacks->reassembled(partial_packet); } } diff --git a/components/bt/bluedroid/include/bt_common_types.h b/components/bt/bluedroid/include/bt_common_types.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/include/bt_target.h b/components/bt/bluedroid/include/bt_target.h index 9d042a2b4c..e684a0ecf4 100644 --- a/components/bt/bluedroid/include/bt_target.h +++ b/components/bt/bluedroid/include/bt_target.h @@ -34,16 +34,62 @@ #include "bdroid_buildcfg.h" #endif +#include "sdkconfig.h" #include "bt_types.h" /* This must be defined AFTER buildcfg.h */ /* Include common GKI definitions used by this platform */ #include "gki_target.h" #include "dyn_mem.h" /* defines static and/or dynamic memory for components */ +#if CONFIG_CLASSIC_BT_ENABLED -#ifndef CLASSIC_BT_INCLUDED -#define CLASSIC_BT_INCLUDED TRUE -#endif ///CLASSIC_BT_INCLUDED +#define BTA_SDP_INCLUDED TRUE +#define BTA_PAN_INCLUDED FALSE +#define BTA_HH_INCLUDED FALSE +#define BTA_AR_INCLUDED TRUE +#define BTA_AV_INCLUDED TRUE +#define BTA_AV_SINK_INCLUDED TRUE +#define SDP_INCLUDED TRUE +#define RFCOMM_INCLUDED FALSE +#define PAN_INCLUDED FALSE +#define HID_HOST_INCLUDED FALSE +#define AVDT_INCLUDED TRUE +#define A2D_INCLUDED TRUE +#define AVCT_INCLUDED TRUE +#define AVRC_INCLUDED TRUE +#define SBC_DEC_INCLUDED TRUE +#define SBC_ENC_INCLUDED FALSE +#define MCA_INCLUDED FALSE +#define BTC_SM_INCLUDED TRUE +#define BTC_PRF_QUEUE_INCLUDED TRUE +#define BTC_GAP_BT_INCLUDED TRUE +#define BTC_AV_INCLUDED TRUE + +#else /* #if CONFIG_CLASSIC_BT_ENABLED */ + +#define BTA_SDP_INCLUDED FALSE +#define BTA_PAN_INCLUDED FALSE +#define BTA_HH_INCLUDED FALSE +#define BTA_AR_INCLUDED FALSE +#define BTA_AV_INCLUDED FALSE +#define BTA_AV_SINK_INCLUDED FALSE +#define SDP_INCLUDED FALSE +#define RFCOMM_INCLUDED FALSE +#define PAN_INCLUDED FALSE +#define HID_HOST_INCLUDED FALSE +#define AVDT_INCLUDED FALSE +#define A2D_INCLUDED FALSE +#define AVCT_INCLUDED FALSE +#define AVRC_INCLUDED FALSE +#define SBC_DEC_INCLUDED FALSE +#define SBC_ENC_INCLUDED FALSE +#define MCA_INCLUDED FALSE +#define BTC_SM_INCLUDED FALSE +#define BTC_PRF_QUEUE_INCLUDED FALSE +#define BTC_GAP_BT_INCLUDED FALSE +#define BTC_AV_INCLUDED FALSE + +#endif /* #if CONFIG_CLASSIC_BT_ENABLED */ //------------------Added from bdroid_buildcfg.h--------------------- #ifndef L2CAP_EXTFEA_SUPPORTED_MASK @@ -91,15 +137,15 @@ #endif #ifndef BTA_AR_INCLUDED -#define BTA_AR_INCLUDED FALSE//TRUE +#define BTA_AR_INCLUDED TRUE//TRUE #endif #ifndef BTA_AV_INCLUDED -#define BTA_AV_INCLUDED FALSE//TRUE +#define BTA_AV_INCLUDED TRUE//TRUE #endif #ifndef BTA_AV_SINK_INCLUDED -#define BTA_AV_SINK_INCLUDED FALSE//FALSE +#define BTA_AV_SINK_INCLUDED TRUE//FALSE #endif #ifndef BTA_DISABLE_DELAY @@ -466,7 +512,7 @@ #define BTM_DEFAULT_DISC_INTERVAL 0x0800 #endif -/* Default class of device +/* * {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS} * * SERVICE_CLASS:0x5A (Bit17 -Networking,Bit19 - Capturing,Bit20 -Object Transfer,Bit22 -Telephony) @@ -474,8 +520,20 @@ * MINOR_CLASS:0x0C - SMART_PHONE * */ +#define BTA_DM_COD_SMARTPHONE {0x5A, 0x02, 0x0C} + +/* +* {SERVICE_CLASS, MAJOR_CLASS, MINOR_CLASS} +* +* SERVICE_CLASS:0x2C (Bit21 - Audio, Bit19 - Capturing) +* MAJOR_CLASS:0x04 - Audio/Video +* MINOR_CLASS:0x05 - LoudSpeaker +*/ +#define BTA_DM_COD_LOUDSPEAKER {0x2C, 0x04, 0x14} + +/* Default class of device */ #ifndef BTA_DM_COD -#define BTA_DM_COD {0x5A, 0x02, 0x0C} +#define BTA_DM_COD BTA_DM_COD_LOUDSPEAKER #endif /* The number of SCO links. */ @@ -573,7 +631,7 @@ /* The IO capability of the local device (for Simple Pairing) */ #ifndef BTM_LOCAL_IO_CAPS -#define BTM_LOCAL_IO_CAPS BTM_IO_CAP_IO +#define BTM_LOCAL_IO_CAPS BTM_IO_CAP_NONE #endif #ifndef BTM_LOCAL_IO_CAPS_BLE @@ -978,7 +1036,7 @@ ******************************************************************************/ #ifndef SDP_INCLUDED -#define SDP_INCLUDED FALSE //TRUE +#define SDP_INCLUDED TRUE #endif /* This is set to enable SDP server functionality. */ @@ -1001,16 +1059,16 @@ /* The maximum number of SDP records the server can support. */ #ifndef SDP_MAX_RECORDS -#define SDP_MAX_RECORDS 15 /*max is 30*/ +#define SDP_MAX_RECORDS 6 /*max is 30*/ #endif /* The maximum number of attributes in each record. */ #ifndef SDP_MAX_REC_ATTR -#define SDP_MAX_REC_ATTR 25 +#define SDP_MAX_REC_ATTR 8 #endif #ifndef SDP_MAX_PAD_LEN -#define SDP_MAX_PAD_LEN 600 +#define SDP_MAX_PAD_LEN 300 #endif /* The maximum length, in bytes, of an attribute. */ @@ -1326,17 +1384,17 @@ Range: 2 octets ******************************************************************************/ #ifndef AVDT_INCLUDED -#define AVDT_INCLUDED FALSE//TRUE +#define AVDT_INCLUDED TRUE #endif /* Include reporting capability in AVDTP */ #ifndef AVDT_REPORTING -#define AVDT_REPORTING FALSE//TRUE +#define AVDT_REPORTING TRUE #endif /* Include multiplexing capability in AVDTP */ #ifndef AVDT_MULTIPLEXING -#define AVDT_MULTIPLEXING FALSE//TRUE +#define AVDT_MULTIPLEXING TRUE #endif /* Number of simultaneous links to different peer devices. */ @@ -1593,7 +1651,7 @@ Range: 2 octets ** ******************************************************************************/ #ifndef AVRC_INCLUDED -#define AVRC_INCLUDED FALSE +#define AVRC_INCLUDED TRUE #endif #ifndef AVRC_METADATA_INCLUDED diff --git a/components/bt/bluedroid/include/bte_appl.h b/components/bt/bluedroid/include/bte_appl.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/include/gki_target.h b/components/bt/bluedroid/include/gki_target.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/osi/config.c b/components/bt/bluedroid/osi/config.c new file mode 100644 index 0000000000..7c876b8430 --- /dev/null +++ b/components/bt/bluedroid/osi/config.c @@ -0,0 +1,547 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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. + +#define LOG_TAG "bt_osi_config" +#include "esp_system.h" +#include "nvs_flash.h" +#include "nvs.h" + +#include +#include +#include +#include +#include + +#include "allocator.h" +#include "config.h" +#include "list.h" +#include "bt_trace.h" + +#define CONFIG_FILE_MAX_SIZE (1024) +#define CONFIG_KEY "bt_cfg_key" +typedef struct { + char *key; + char *value; +} entry_t; + +typedef struct { + char *name; + list_t *entries; +} section_t; + +struct config_t { + list_t *sections; +}; + +// Empty definition; this type is aliased to list_node_t. +struct config_section_iter_t {}; + +static void config_parse(nvs_handle fp, config_t *config); + +static section_t *section_new(const char *name); +static void section_free(void *ptr); +static section_t *section_find(const config_t *config, const char *section); + +static entry_t *entry_new(const char *key, const char *value); +static void entry_free(void *ptr); +static entry_t *entry_find(const config_t *config, const char *section, const char *key); + +config_t *config_new_empty(void) +{ + config_t *config = osi_calloc(sizeof(config_t)); + if (!config) { + LOG_ERROR("%s unable to allocate memory for config_t.\n", __func__); + goto error; + } + + config->sections = list_new(section_free); + if (!config->sections) { + LOG_ERROR("%s unable to allocate list for sections.\n", __func__); + goto error; + } + + return config; + +error:; + config_free(config); + return NULL; +} + +config_t *config_new(const char *filename) +{ + assert(filename != NULL); + + config_t *config = config_new_empty(); + if (!config) { + return NULL; + } + + esp_err_t err; + nvs_handle fp; + err = nvs_open(filename, NVS_READWRITE, &fp); + if (err != ESP_OK) { + LOG_ERROR("%s unable to open file '%s'\n", __func__, filename); + config_free(config); + return NULL; + } + + config_parse(fp, config); + nvs_close(fp); + return config; +} + +void config_free(config_t *config) +{ + if (!config) { + return; + } + + list_free(config->sections); + osi_free(config); +} + +bool config_has_section(const config_t *config, const char *section) +{ + assert(config != NULL); + assert(section != NULL); + + return (section_find(config, section) != NULL); +} + +bool config_has_key(const config_t *config, const char *section, const char *key) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + return (entry_find(config, section, key) != NULL); +} + +int config_get_int(const config_t *config, const char *section, const char *key, int def_value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + entry_t *entry = entry_find(config, section, key); + if (!entry) { + return def_value; + } + + char *endptr; + int ret = strtol(entry->value, &endptr, 0); + return (*endptr == '\0') ? ret : def_value; +} + +bool config_get_bool(const config_t *config, const char *section, const char *key, bool def_value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + entry_t *entry = entry_find(config, section, key); + if (!entry) { + return def_value; + } + + if (!strcmp(entry->value, "true")) { + return true; + } + if (!strcmp(entry->value, "false")) { + return false; + } + + return def_value; +} + +const char *config_get_string(const config_t *config, const char *section, const char *key, const char *def_value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + entry_t *entry = entry_find(config, section, key); + if (!entry) { + return def_value; + } + + return entry->value; +} + +void config_set_int(config_t *config, const char *section, const char *key, int value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + char value_str[32] = { 0 }; + sprintf(value_str, "%d", value); + config_set_string(config, section, key, value_str, false); +} + +void config_set_bool(config_t *config, const char *section, const char *key, bool value) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + config_set_string(config, section, key, value ? "true" : "false", false); +} + +void config_set_string(config_t *config, const char *section, const char *key, const char *value, bool insert_back) +{ + section_t *sec = section_find(config, section); + if (!sec) { + sec = section_new(section); + if (insert_back) { + list_append(config->sections, sec); + } else { + list_prepend(config->sections, sec); + } + } + + for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) { + entry_t *entry = list_node(node); + if (!strcmp(entry->key, key)) { + osi_free(entry->value); + entry->value = osi_strdup(value); + return; + } + } + + entry_t *entry = entry_new(key, value); + list_append(sec->entries, entry); +} + +bool config_remove_section(config_t *config, const char *section) +{ + assert(config != NULL); + assert(section != NULL); + + section_t *sec = section_find(config, section); + if (!sec) { + return false; + } + + return list_remove(config->sections, sec); +} + +bool config_remove_key(config_t *config, const char *section, const char *key) +{ + assert(config != NULL); + assert(section != NULL); + assert(key != NULL); + + section_t *sec = section_find(config, section); + entry_t *entry = entry_find(config, section, key); + if (!sec || !entry) { + return false; + } + + return list_remove(sec->entries, entry); +} + +const config_section_node_t *config_section_begin(const config_t *config) +{ + assert(config != NULL); + return (const config_section_node_t *)list_begin(config->sections); +} + +const config_section_node_t *config_section_end(const config_t *config) +{ + assert(config != NULL); + return (const config_section_node_t *)list_end(config->sections); +} + +const config_section_node_t *config_section_next(const config_section_node_t *node) +{ + assert(node != NULL); + return (const config_section_node_t *)list_next((const list_node_t *)node); +} + +const char *config_section_name(const config_section_node_t *node) +{ + assert(node != NULL); + const list_node_t *lnode = (const list_node_t *)node; + const section_t *section = (const section_t *)list_node(lnode); + return section->name; +} + +bool config_save(const config_t *config, const char *filename) +{ + assert(config != NULL); + assert(filename != NULL); + assert(*filename != '\0'); + + esp_err_t err; + int err_code = 0; + nvs_handle fp; + char *line = osi_calloc(1024); + char *buf = osi_calloc(CONFIG_FILE_MAX_SIZE); + if (!line || !buf) { + err_code |= 0x01; + goto error; + } + + err = nvs_open(filename, NVS_READWRITE, &fp); + if (err != ESP_OK) { + err_code |= 0x02; + goto error; + } + + int w_cnt, w_cnt_total = 0; + for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) { + const section_t *section = (const section_t *)list_node(node); + LOG_DEBUG("section name: %s\n", section->name); + w_cnt = snprintf(line, 1024, "[%s]\n", section->name); + if (w_cnt + w_cnt_total < CONFIG_FILE_MAX_SIZE) { + memcpy(buf + w_cnt_total, line, w_cnt); + w_cnt_total += w_cnt; + } else { + break; + } + + for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) { + const entry_t *entry = (const entry_t *)list_node(enode); + LOG_DEBUG("(key, val): (%s, %s)\n", entry->key, entry->value); + w_cnt = snprintf(line, 1024, "%s = %s\n", entry->key, entry->value); + if (w_cnt + w_cnt_total < CONFIG_FILE_MAX_SIZE) { + memcpy(buf + w_cnt_total, line, w_cnt); + w_cnt_total += w_cnt; + } else { + break; + } + } + + // Only add a separating newline if there are more sections. + if (list_next(node) != list_end(config->sections)) { + if (1 + w_cnt_total < CONFIG_FILE_MAX_SIZE) { + buf[w_cnt_total] = '\n'; + w_cnt_total += 1; + } + } else { + break; + } + } + + buf[w_cnt_total] = '\0'; + + err = nvs_set_blob(fp, CONFIG_KEY, buf, w_cnt_total); + + if (err != ESP_OK) { + nvs_close(fp); + err_code |= 0x04; + goto error; + } + + err = nvs_commit(fp); + if (err != ESP_OK) { + nvs_close(fp); + err_code |= 0x08; + goto error; + } + + nvs_close(fp); + osi_free(line); + osi_free(buf); + return true; + +error: + if (buf) { + osi_free(buf); + } + if (line) { + osi_free(line); + } + if (err_code) { + LOG_ERROR("%s, err_code: 0x%x\n", __func__, err_code); + } + return false; +} + +static char *trim(char *str) +{ + while (isspace((unsigned char)(*str))) { + ++str; + } + + if (!*str) { + return str; + } + + char *end_str = str + strlen(str) - 1; + while (end_str > str && isspace((unsigned char)(*end_str))) { + --end_str; + } + + end_str[1] = '\0'; + return str; +} + +static void config_parse(nvs_handle fp, config_t *config) +{ + assert(fp != 0); + assert(config != NULL); + + int line_num = 0; + int err_code = 0; + char *line = osi_calloc(1024); + char *section = osi_calloc(1024); + char *buf = osi_calloc(CONFIG_FILE_MAX_SIZE); + if (!line || !section || !buf) { + err_code |= 0x01; + goto error; + } + + esp_err_t err; + size_t length = CONFIG_FILE_MAX_SIZE; + err = nvs_get_blob(fp, CONFIG_KEY, buf, &length); + if (err != ESP_OK) { + err_code |= 0x02; + goto error; + } + + char *p_line_end; + char *p_line_bgn = buf; + strcpy(section, CONFIG_DEFAULT_SECTION); + + while ( (p_line_bgn < buf + length - 1) && (p_line_end = strchr(p_line_bgn, '\n'))) { + + // get one line + int line_len = p_line_end - p_line_bgn; + if (line_len > 1023) { + LOG_WARN("%s exceed max line length on line %d.\n", __func__, line_num); + break; + } + memcpy(line, p_line_bgn, line_len); + line[line_len] = '\0'; + p_line_bgn = p_line_end + 1; + char *line_ptr = trim(line); + ++line_num; + + // Skip blank and comment lines. + if (*line_ptr == '\0' || *line_ptr == '#') { + continue; + } + + if (*line_ptr == '[') { + size_t len = strlen(line_ptr); + if (line_ptr[len - 1] != ']') { + LOG_WARN("%s unterminated section name on line %d.\n", __func__, line_num); + continue; + } + strncpy(section, line_ptr + 1, len - 2); + section[len - 2] = '\0'; + } else { + char *split = strchr(line_ptr, '='); + if (!split) { + LOG_DEBUG("%s no key/value separator found on line %d.\n", __func__, line_num); + continue; + } + *split = '\0'; + config_set_string(config, section, trim(line_ptr), trim(split + 1), true); + } + } + +error: + if (buf) { + osi_free(buf); + } + if (line) { + osi_free(line); + } + if (section) { + osi_free(section); + } + if (err_code) { + LOG_ERROR("%s returned with err code: %d\n", __func__, err_code); + } +} + +static section_t *section_new(const char *name) +{ + section_t *section = osi_calloc(sizeof(section_t)); + if (!section) { + return NULL; + } + + section->name = osi_strdup(name); + section->entries = list_new(entry_free); + return section; +} + +static void section_free(void *ptr) +{ + if (!ptr) { + return; + } + + section_t *section = ptr; + osi_free(section->name); + list_free(section->entries); + osi_free(section); +} + +static section_t *section_find(const config_t *config, const char *section) +{ + for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) { + section_t *sec = list_node(node); + if (!strcmp(sec->name, section)) { + return sec; + } + } + + return NULL; +} + +static entry_t *entry_new(const char *key, const char *value) +{ + entry_t *entry = osi_calloc(sizeof(entry_t)); + if (!entry) { + return NULL; + } + + entry->key = osi_strdup(key); + entry->value = osi_strdup(value); + return entry; +} + +static void entry_free(void *ptr) +{ + if (!ptr) { + return; + } + + entry_t *entry = ptr; + osi_free(entry->key); + osi_free(entry->value); + osi_free(entry); +} + +static entry_t *entry_find(const config_t *config, const char *section, const char *key) +{ + section_t *sec = section_find(config, section); + if (!sec) { + return NULL; + } + + for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) { + entry_t *entry = list_node(node); + if (!strcmp(entry->key, key)) { + return entry; + } + } + + return NULL; +} diff --git a/components/bt/bluedroid/osi/include/alarm.h b/components/bt/bluedroid/osi/include/alarm.h index 35c0f4666b..937874f219 100644 --- a/components/bt/bluedroid/osi/include/alarm.h +++ b/components/bt/bluedroid/osi/include/alarm.h @@ -26,7 +26,7 @@ typedef uint32_t period_ms_t; typedef void (*osi_alarm_callback_t)(void *data); -#define ALARM_CBS_NUM 20 +#define ALARM_CBS_NUM 30 #define ALARM_ID_BASE 1000 typedef struct alarm_t { /* timer id point to here */ diff --git a/components/bt/bluedroid/osi/include/buffer.h b/components/bt/bluedroid/osi/include/buffer.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/osi/include/config.h b/components/bt/bluedroid/osi/include/config.h new file mode 100644 index 0000000000..4f0e2cd8ae --- /dev/null +++ b/components/bt/bluedroid/osi/include/config.h @@ -0,0 +1,144 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __CONFIG_H__ +#define __CONFIG_H__ + +// This module implements a configuration parser. Clients can query the +// contents of a configuration file through the interface provided here. +// The current implementation is read-only; mutations are only kept in +// memory. This parser supports the INI file format. + +// Implementation notes: +// - Key/value pairs that are not within a section are assumed to be under +// the |CONFIG_DEFAULT_SECTION| section. +// - Multiple sections with the same name will be merged as if they were in +// a single section. +// - Empty sections with no key/value pairs will be treated as if they do +// not exist. In other words, |config_has_section| will return false for +// empty sections. +// - Duplicate keys in a section will overwrite previous values. +// - All strings are case sensitive. + +#include + +// The default section name to use if a key/value pair is not defined within +// a section. +#define CONFIG_DEFAULT_SECTION "Global" + +typedef struct config_t config_t; +typedef struct config_section_node_t config_section_node_t; + +// Creates a new config object with no entries (i.e. not backed by a file). +// This function returns a config object or NULL on error. Clients must call +// |config_free| on the returned handle when it is no longer required. +config_t *config_new_empty(void); + +// Loads the specified file and returns a handle to the config file. If there +// was a problem loading the file or allocating memory, this function returns +// NULL. Clients must call |config_free| on the returned handle when it is no +// longer required. |filename| must not be NULL and must point to a readable +// file on the filesystem. +config_t *config_new(const char *filename); + +// Frees resources associated with the config file. No further operations may +// be performed on the |config| object after calling this function. |config| +// may be NULL. +void config_free(config_t *config); + +// Returns true if the config file contains a section named |section|. If +// the section has no key/value pairs in it, this function will return false. +// |config| and |section| must not be NULL. +bool config_has_section(const config_t *config, const char *section); + +// Returns true if the config file has a key named |key| under |section|. +// Returns false otherwise. |config|, |section|, and |key| must not be NULL. +bool config_has_key(const config_t *config, const char *section, const char *key); + +// Returns the integral value for a given |key| in |section|. If |section| +// or |key| do not exist, or the value cannot be fully converted to an integer, +// this function returns |def_value|. |config|, |section|, and |key| must not +// be NULL. +int config_get_int(const config_t *config, const char *section, const char *key, int def_value); + +// Returns the boolean value for a given |key| in |section|. If |section| +// or |key| do not exist, or the value cannot be converted to a boolean, this +// function returns |def_value|. |config|, |section|, and |key| must not be NULL. +bool config_get_bool(const config_t *config, const char *section, const char *key, bool def_value); + +// Returns the string value for a given |key| in |section|. If |section| or +// |key| do not exist, this function returns |def_value|. The returned string +// is owned by the config module and must not be freed. |config|, |section|, +// and |key| must not be NULL. |def_value| may be NULL. +const char *config_get_string(const config_t *config, const char *section, const char *key, const char *def_value); + +// Sets an integral value for the |key| in |section|. If |key| or |section| do +// not already exist, this function creates them. |config|, |section|, and |key| +// must not be NULL. +void config_set_int(config_t *config, const char *section, const char *key, int value); + +// Sets a boolean value for the |key| in |section|. If |key| or |section| do +// not already exist, this function creates them. |config|, |section|, and |key| +// must not be NULL. +void config_set_bool(config_t *config, const char *section, const char *key, bool value); + +// Sets a string value for the |key| in |section|. If |key| or |section| do +// not already exist, this function creates them. |config|, |section|, |key|, and +// |value| must not be NULL. +void config_set_string(config_t *config, const char *section, const char *key, const char *value, bool insert_back); + +// Removes |section| from the |config| (and, as a result, all keys in the section). +// Returns true if |section| was found and removed from |config|, false otherwise. +// Neither |config| nor |section| may be NULL. +bool config_remove_section(config_t *config, const char *section); + +// Removes one specific |key| residing in |section| of the |config|. Returns true +// if the section and key were found and the key was removed, false otherwise. +// None of |config|, |section|, or |key| may be NULL. +bool config_remove_key(config_t *config, const char *section, const char *key); + +// Returns an iterator to the first section in the config file. If there are no +// sections, the iterator will equal the return value of |config_section_end|. +// The returned pointer must be treated as an opaque handle and must not be freed. +// The iterator is invalidated on any config mutating operation. |config| may not +// be NULL. +const config_section_node_t *config_section_begin(const config_t *config); + +// Returns an iterator to one past the last section in the config file. It does not +// represent a valid section, but can be used to determine if all sections have been +// iterated over. The returned pointer must be treated as an opaque handle and must +// not be freed and must not be iterated on (must not call |config_section_next| on +// it). |config| may not be NULL. +const config_section_node_t *config_section_end(const config_t *config); + +// Moves |iter| to the next section. If there are no more sections, |iter| will +// equal the value of |config_section_end|. |iter| may not be NULL and must be +// a pointer returned by either |config_section_begin| or |config_section_next|. +const config_section_node_t *config_section_next(const config_section_node_t *iter); + +// Returns the name of the section referred to by |iter|. The returned pointer is +// owned by the config module and must not be freed by the caller. The pointer will +// remain valid until |config_free| is called. |iter| may not be NULL and must not +// equal the value returned by |config_section_end|. +const char *config_section_name(const config_section_node_t *iter); + +// Saves |config| to a file given by |filename|. Note that this could be a destructive +// operation: if |filename| already exists, it will be overwritten. The config +// module does not preserve comments or formatting so if a config file was opened +// with |config_new| and subsequently overwritten with |config_save|, all comments +// and special formatting in the original file will be lost. Neither |config| nor +// |filename| may be NULL. +bool config_save(const config_t *config, const char *filename); + +#endif /* #ifndef __CONFIG_H__ */ diff --git a/components/bt/bluedroid/osi/include/fixed_queue.h b/components/bt/bluedroid/osi/include/fixed_queue.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/osi/include/hash_functions.h b/components/bt/bluedroid/osi/include/hash_functions.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/osi/include/list.h b/components/bt/bluedroid/osi/include/list.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/osi/include/osi.h b/components/bt/bluedroid/osi/include/osi.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/osi/include/osi_arch.h b/components/bt/bluedroid/osi/include/osi_arch.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/osi/include/thread.h b/components/bt/bluedroid/osi/include/thread.h index c148cef70c..f1e743fe4e 100644 --- a/components/bt/bluedroid/osi/include/thread.h +++ b/components/bt/bluedroid/osi/include/thread.h @@ -40,7 +40,6 @@ enum { SIG_PRF_WORK = 0xfd, SIG_BTU_START_UP = 0xfe, SIG_BTU_WORK = 0xff, - SIG_BTIF_WORK = 0xff }; #define HCI_HOST_TASK_STACK_SIZE (2048 + BT_TASK_EXTRA_STACK_SIZE) diff --git a/components/bt/bluedroid/stack/a2dp/a2d_api.c b/components/bt/bluedroid/stack/a2dp/a2d_api.c new file mode 100644 index 0000000000..5f403cc6d3 --- /dev/null +++ b/components/bt/bluedroid/stack/a2dp/a2d_api.c @@ -0,0 +1,388 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * ommon API for the Advanced Audio Distribution Profile (A2DP) + * + ******************************************************************************/ +#include +#include "bt_target.h" +#include "sdpdefs.h" +#include "a2d_api.h" +#include "a2d_int.h" +#include "avdt_api.h" + +#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) + +/***************************************************************************** +** Global data +*****************************************************************************/ +#if A2D_DYNAMIC_MEMORY == FALSE +tA2D_CB a2d_cb; +#endif + + +/****************************************************************************** +** +** Function a2d_sdp_cback +** +** Description This is the SDP callback function used by A2D_FindService. +** This function will be executed by SDP when the service +** search is completed. If the search is successful, it +** finds the first record in the database that matches the +** UUID of the search. Then retrieves various parameters +** from the record. When it is finished it calls the +** application callback function. +** +** Returns Nothing. +** +******************************************************************************/ +static void a2d_sdp_cback(UINT16 status) +{ + tSDP_DISC_REC *p_rec = NULL; + tSDP_DISC_ATTR *p_attr; + BOOLEAN found = FALSE; + tA2D_Service a2d_svc; + tSDP_PROTOCOL_ELEM elem; + + A2D_TRACE_API("a2d_sdp_cback status: %d", status); + + if (status == SDP_SUCCESS) { + /* loop through all records we found */ + do { + /* get next record; if none found, we're done */ + if ((p_rec = SDP_FindServiceInDb(a2d_cb.find.p_db, + a2d_cb.find.service_uuid, p_rec)) == NULL) { + break; + } + memset(&a2d_svc, 0, sizeof(tA2D_Service)); + + /* get service name */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, + ATTR_ID_SERVICE_NAME)) != NULL) { + a2d_svc.p_service_name = (char *) p_attr->attr_value.v.array; + a2d_svc.service_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); + } + + /* get provider name */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, + ATTR_ID_PROVIDER_NAME)) != NULL) { + a2d_svc.p_provider_name = (char *) p_attr->attr_value.v.array; + a2d_svc.provider_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type); + } + + /* get supported features */ + if ((p_attr = SDP_FindAttributeInRec(p_rec, + ATTR_ID_SUPPORTED_FEATURES)) != NULL) { + a2d_svc.features = p_attr->attr_value.v.u16; + } + + /* get AVDTP version */ + if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_AVDTP, &elem)) { + a2d_svc.avdt_version = elem.params[0]; + A2D_TRACE_DEBUG("avdt_version: 0x%x", a2d_svc.avdt_version); + } + + /* we've got everything, we're done */ + found = TRUE; + break; + + } while (TRUE); + } + + a2d_cb.find.service_uuid = 0; + /* return info from sdp record in app callback function */ + if (a2d_cb.find.p_cback != NULL) { + (*a2d_cb.find.p_cback)(found, &a2d_svc); + } + + return; +} + +/******************************************************************************* +** +** Function a2d_set_avdt_sdp_ver +** +** Description This function allows the script wrapper to change the +** avdt version of a2dp. +** +** Returns None +** +*******************************************************************************/ +void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver) +{ + a2d_cb.avdt_sdp_ver = avdt_sdp_ver; +} + +/****************************************************************************** +** +** Function A2D_AddRecord +** +** Description This function is called by a server application to add +** SRC or SNK information to an SDP record. Prior to +** calling this function the application must call +** SDP_CreateRecord() to create an SDP record. +** +** Input Parameters: +** service_uuid: Indicates SRC or SNK. +** +** p_service_name: Pointer to a null-terminated character +** string containing the service name. +** +** p_provider_name: Pointer to a null-terminated character +** string containing the provider name. +** +** features: Profile supported features. +** +** sdp_handle: SDP handle returned by SDP_CreateRecord(). +** +** Output Parameters: +** None. +** +** Returns A2D_SUCCESS if function execution succeeded, +** A2D_INVALID_PARAMS if bad parameters are given. +** A2D_FAIL if function execution failed. +** +******************************************************************************/ +tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name, + UINT16 features, UINT32 sdp_handle) +{ + UINT16 browse_list[1]; + BOOLEAN result = TRUE; + UINT8 temp[8]; + UINT8 *p; + tSDP_PROTOCOL_ELEM proto_list [A2D_NUM_PROTO_ELEMS]; + + A2D_TRACE_API("A2D_AddRecord uuid: %x", service_uuid); + + if ( (sdp_handle == 0) || + (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) ) { + return A2D_INVALID_PARAMS; + } + + /* add service class id list */ + result &= SDP_AddServiceClassIdList(sdp_handle, 1, &service_uuid); + + memset((void *) proto_list, 0 , A2D_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM)); + + /* add protocol descriptor list */ + proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; + proto_list[0].num_params = 1; + proto_list[0].params[0] = AVDT_PSM; + proto_list[1].protocol_uuid = UUID_PROTOCOL_AVDTP; + proto_list[1].num_params = 1; + proto_list[1].params[0] = a2d_cb.avdt_sdp_ver; + + result &= SDP_AddProtocolList(sdp_handle, A2D_NUM_PROTO_ELEMS, proto_list); + + /* add profile descriptor list */ + result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION, A2D_VERSION); + + /* add supported feature */ + if (features != 0) { + p = temp; + UINT16_TO_BE_STREAM(p, features); + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, + (UINT32)2, (UINT8 *)temp); + } + + /* add provider name */ + if (p_provider_name != NULL) { + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_provider_name) + 1), (UINT8 *) p_provider_name); + } + + /* add service name */ + if (p_service_name != NULL) { + result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, + (UINT32)(strlen(p_service_name) + 1), (UINT8 *) p_service_name); + } + + /* add browse group list */ + browse_list[0] = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; + result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list); + + + return (result ? A2D_SUCCESS : A2D_FAIL); +} + +/****************************************************************************** +** +** Function A2D_FindService +** +** Description This function is called by a client application to +** perform service discovery and retrieve SRC or SNK SDP +** record information from a server. Information is +** returned for the first service record found on the +** server that matches the service UUID. The callback +** function will be executed when service discovery is +** complete. There can only be one outstanding call to +** A2D_FindService() at a time; the application must wait +** for the callback before it makes another call to +** the function. +** +** Input Parameters: +** service_uuid: Indicates SRC or SNK. +** +** bd_addr: BD address of the peer device. +** +** p_db: Pointer to the information to initialize +** the discovery database. +** +** p_cback: Pointer to the A2D_FindService() +** callback function. +** +** Output Parameters: +** None. +** +** Returns A2D_SUCCESS if function execution succeeded, +** A2D_INVALID_PARAMS if bad parameters are given. +** A2D_BUSY if discovery is already in progress. +** A2D_FAIL if function execution failed. +** +******************************************************************************/ +tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr, + tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback) +{ + tSDP_UUID uuid_list; + BOOLEAN result = TRUE; + UINT16 a2d_attr_list[] = {ATTR_ID_SERVICE_CLASS_ID_LIST, /* update A2D_NUM_ATTR, if changed */ + ATTR_ID_BT_PROFILE_DESC_LIST, + ATTR_ID_SUPPORTED_FEATURES, + ATTR_ID_SERVICE_NAME, + ATTR_ID_PROTOCOL_DESC_LIST, + ATTR_ID_PROVIDER_NAME + }; + + A2D_TRACE_API("A2D_FindService uuid: %x", service_uuid); + if ( (service_uuid != UUID_SERVCLASS_AUDIO_SOURCE && service_uuid != UUID_SERVCLASS_AUDIO_SINK) || + p_db == NULL || p_db->p_db == NULL || p_cback == NULL) { + return A2D_INVALID_PARAMS; + } + + if ( a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SOURCE || + a2d_cb.find.service_uuid == UUID_SERVCLASS_AUDIO_SINK) { + return A2D_BUSY; + } + + /* set up discovery database */ + uuid_list.len = LEN_UUID_16; + uuid_list.uu.uuid16 = service_uuid; + + if (p_db->p_attrs == NULL || p_db->num_attr == 0) { + p_db->p_attrs = a2d_attr_list; + p_db->num_attr = A2D_NUM_ATTR; + } + + result = SDP_InitDiscoveryDb(p_db->p_db, p_db->db_len, 1, &uuid_list, p_db->num_attr, + p_db->p_attrs); + + if (result == TRUE) { + /* store service_uuid and discovery db pointer */ + a2d_cb.find.p_db = p_db->p_db; + a2d_cb.find.service_uuid = service_uuid; + a2d_cb.find.p_cback = p_cback; + + /* perform service search */ + result = SDP_ServiceSearchAttributeRequest(bd_addr, p_db->p_db, a2d_sdp_cback); + if (FALSE == result) { + a2d_cb.find.service_uuid = 0; + } + } + + return (result ? A2D_SUCCESS : A2D_FAIL); +} + +/****************************************************************************** +** +** Function A2D_SetTraceLevel +** +** Description Sets the trace level for A2D. If 0xff is passed, the +** current trace level is returned. +** +** Input Parameters: +** new_level: The level to set the A2D tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new trace level or current trace level if +** the input parameter is 0xff. +** +******************************************************************************/ +UINT8 A2D_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) { + a2d_cb.trace_level = new_level; + } + + return (a2d_cb.trace_level); +} + +/****************************************************************************** +** Function A2D_BitsSet +** +** Description Check the given num for the number of bits set +** Returns A2D_SET_ONE_BIT, if one and only one bit is set +** A2D_SET_ZERO_BIT, if all bits clear +** A2D_SET_MULTL_BIT, if multiple bits are set +******************************************************************************/ +UINT8 A2D_BitsSet(UINT8 num) +{ + UINT8 count; + BOOLEAN res; + if (num == 0) { + res = A2D_SET_ZERO_BIT; + } else { + count = (num & (num - 1)); + res = ((count == 0) ? A2D_SET_ONE_BIT : A2D_SET_MULTL_BIT); + } + return res; +} + +/******************************************************************************* +** +** Function A2D_Init +** +** Description This function is called to initialize the control block +** for this layer. It must be called before accessing any +** other API functions for this layer. It is typically called +** once during the start up of the stack. +** +** Returns void +** +*******************************************************************************/ +void A2D_Init(void) +{ + memset(&a2d_cb, 0, sizeof(tA2D_CB)); + + a2d_cb.avdt_sdp_ver = AVDT_VERSION; + +#if defined(A2D_INITIAL_TRACE_LEVEL) + a2d_cb.trace_level = A2D_INITIAL_TRACE_LEVEL; +#else + a2d_cb.trace_level = BT_TRACE_LEVEL_NONE; +#endif +} + +#endif /* #if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/a2dp/a2d_sbc.c b/components/bt/bluedroid/stack/a2dp/a2d_sbc.c new file mode 100644 index 0000000000..3a8f694fa5 --- /dev/null +++ b/components/bt/bluedroid/stack/a2dp/a2d_sbc.c @@ -0,0 +1,398 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Utility functions to help build and parse SBC Codec Information Element + * and Media Payload. + * + ******************************************************************************/ + +#include "bt_target.h" + +#include +#include "a2d_api.h" +#include "a2d_int.h" +#include "a2d_sbc.h" +#include "bt_utils.h" + +#if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) + +/************************************************************************************************* + * SBC descramble code + * Purpose: to tie the SBC code with BTE/mobile stack code, + * especially for the case when the SBC is ported into a third-party Multimedia chip + * + * Algorithm: + * init process: all counters reset to 0, + * calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2) + * scramble side: the init process happens every time SBC_Encoder_Init() is called. + * descramble side: it would be nice to know if he "init" process has happened. + * alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100). + * + * scramble process: + * The CRC byte: + * Every SBC frame has a frame header. + * The 1st byte is the sync word and the following 2 bytes are about the stream format. + * They are supposed to be "constant" within a "song" + * The 4th byte is the CRC byte. The CRC byte is bound to be random. + * Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index". + * + * SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame. + * + * The "use" bit is any bit in SBC_PRTC_USE_MASK is set. + * If set, SBC uses the "index" from the current frame. + * If not set, SBC uses the "index" from the previous frame or 0. + * + * index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index + * + * if(index > 0) + * { + * p = &u8frame[base_index]; + * if((index&1)&&(u16PacketLength > (base_index+index*2))) + * { + * // odd index: swap 2 bytes + * tmp = p[index]; + * p[index] = p[index*2]; + * p[index*2] = tmp; + * } + * else + * { + * // even index: shift by 3 + * tmp = (p[index] >> 3) + (p[index] << 5); + * p[index] = tmp; + * } + * } + * //else index is 0. The frame stays unaltered + * + */ +#define A2D_SBC_SYNC_WORD 0x9C +#define A2D_SBC_CRC_IDX 3 +#define A2D_SBC_USE_MASK 0x64 +#define A2D_SBC_SYNC_MASK 0x10 +#define A2D_SBC_CIDX 0 +#define A2D_SBC_LIDX 1 +#define A2D_SBC_CH_M_BITS 0xC /* channel mode bits: 0: mono; 1 ch */ +#define A2D_SBC_SUBBAND_BIT 0x1 /* num of subband bit: 0:4; 1: 8 */ + +#define A2D_SBC_GET_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2)) + +typedef struct { + UINT8 use; + UINT8 idx; +} tA2D_SBC_FR_CB; + +typedef struct { + tA2D_SBC_FR_CB fr[2]; + UINT8 index; + UINT8 base; +} tA2D_SBC_DS_CB; + +static tA2D_SBC_DS_CB a2d_sbc_ds_cb; +/*int a2d_count = 0;*/ +/****************************************************************************** +** +** Function A2D_SbcChkFrInit +** +** Description check if need to init the descramble control block. +** +** Returns nothing. +******************************************************************************/ +void A2D_SbcChkFrInit(UINT8 *p_pkt) +{ + UINT8 fmt; + UINT8 num_chnl = 1; + UINT8 num_subband = 4; + + if ((p_pkt[0] & A2D_SBC_SYNC_MASK) == 0) { + a2d_cb.use_desc = TRUE; + fmt = p_pkt[1]; + p_pkt[0] |= A2D_SBC_SYNC_MASK; + memset(&a2d_sbc_ds_cb, 0, sizeof(tA2D_SBC_DS_CB)); + if (fmt & A2D_SBC_CH_M_BITS) { + num_chnl = 2; + } + if (fmt & A2D_SBC_SUBBAND_BIT) { + num_subband = 8; + } + a2d_sbc_ds_cb.base = 6 + num_chnl * num_subband / 2; + /*printf("base: %d\n", a2d_sbc_ds_cb.base); + a2d_count = 0;*/ + } +} + +/****************************************************************************** +** +** Function A2D_SbcDescramble +** +** Description descramble the packet. +** +** Returns nothing. +******************************************************************************/ +void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len) +{ + tA2D_SBC_FR_CB *p_cur, *p_last; + UINT32 idx, tmp, tmp2; + + if (a2d_cb.use_desc) { + /* c2l */ + p_last = &a2d_sbc_ds_cb.fr[A2D_SBC_LIDX]; + p_cur = &a2d_sbc_ds_cb.fr[A2D_SBC_CIDX]; + p_last->idx = p_cur->idx; + p_last->use = p_cur->use; + /* getc */ + p_cur->use = p_pkt[A2D_SBC_CRC_IDX] & A2D_SBC_USE_MASK; + p_cur->idx = A2D_SBC_GET_IDX(p_pkt[A2D_SBC_CRC_IDX]); + a2d_sbc_ds_cb.index = (p_cur->use) ? A2D_SBC_CIDX : A2D_SBC_LIDX; + /* + printf("%05d: ar[%02d]: x%02x, msk: x%02x, use: %s, idx: %02d, ", + a2d_count++, + A2D_SBC_CRC_IDX, p_pkt[A2D_SBC_CRC_IDX], A2D_SBC_USE_MASK, + (p_cur->use)?"cur":"lst", p_cur->idx); + */ + /* descramble */ + idx = a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx; + if (idx > 0) { + p_pkt = &p_pkt[a2d_sbc_ds_cb.base]; + if ((idx & 1) && (len > (a2d_sbc_ds_cb.base + (idx << 1)))) { + tmp2 = (idx << 1); + tmp = p_pkt[idx]; + p_pkt[idx] = p_pkt[tmp2]; + p_pkt[tmp2] = tmp; + /* + printf("tmp2: %02d, len: %d, idx: %d\n", + tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx); + */ + } else { + tmp2 = p_pkt[idx]; + tmp = (tmp2 >> 3) + (tmp2 << 5); + p_pkt[idx] = (UINT8)tmp; + /* + printf("tmp: x%02x, len: %d, idx: %d(cmp:%d)\n", + (UINT8)tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx, + (a2d_sbc_ds_cb.base+(idx<<1))); + */ + } + } + /* + else + { + printf("!!!!\n"); + } + */ + } +} + +/****************************************************************************** +** +** Function A2D_BldSbcInfo +** +** Description This function is called by an application to build +** the SBC Media Codec Capabilities byte sequence +** beginning from the LOSC octet. +** Input Parameters: +** media_type: Indicates Audio, or Multimedia. +** +** p_ie: The SBC Codec Information Element information. +** +** Output Parameters: +** p_result: the resulting codec info byte sequence. +** +** Returns A2D_SUCCESS if function execution succeeded. +** Error status code, otherwise. +******************************************************************************/ +tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie, UINT8 *p_result) +{ + tA2D_STATUS status; + + if ( p_ie == NULL || p_result == NULL || + (p_ie->samp_freq & ~A2D_SBC_IE_SAMP_FREQ_MSK) || + (p_ie->ch_mode & ~A2D_SBC_IE_CH_MD_MSK) || + (p_ie->block_len & ~A2D_SBC_IE_BLOCKS_MSK) || + (p_ie->num_subbands & ~A2D_SBC_IE_SUBBAND_MSK) || + (p_ie->alloc_mthd & ~A2D_SBC_IE_ALLOC_MD_MSK) || + (p_ie->max_bitpool < p_ie->min_bitpool) || + (p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL) || + (p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL) || + (p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL) || + (p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL) ) { + /* if any unused bit is set */ + status = A2D_INVALID_PARAMS; + } else { + status = A2D_SUCCESS; + *p_result++ = A2D_SBC_INFO_LEN; + *p_result++ = media_type; + *p_result++ = A2D_MEDIA_CT_SBC; + + /* Media Codec Specific Information Element */ + *p_result++ = p_ie->samp_freq | p_ie->ch_mode; + + *p_result++ = p_ie->block_len | p_ie->num_subbands | p_ie->alloc_mthd; + + *p_result++ = p_ie->min_bitpool; + *p_result = p_ie->max_bitpool; + } + return status; +} + +/****************************************************************************** +** +** Function A2D_ParsSbcInfo +** +** Description This function is called by an application to parse +** the SBC Media Codec Capabilities byte sequence +** beginning from the LOSC octet. +** Input Parameters: +** p_info: the byte sequence to parse. +** +** for_caps: TRUE, if the byte sequence is for get capabilities response. +** +** Output Parameters: +** p_ie: The SBC Codec Information Element information. +** +** Returns A2D_SUCCESS if function execution succeeded. +** Error status code, otherwise. +******************************************************************************/ +tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps) +{ + tA2D_STATUS status; + UINT8 losc; + + if ( p_ie == NULL || p_info == NULL) { + status = A2D_INVALID_PARAMS; + } else { + losc = *p_info++; + p_info++; + /* If the function is called for the wrong Media Type or Media Codec Type */ + if (losc != A2D_SBC_INFO_LEN || *p_info != A2D_MEDIA_CT_SBC) { + status = A2D_WRONG_CODEC; + } else { + p_info++; + p_ie->samp_freq = *p_info & A2D_SBC_IE_SAMP_FREQ_MSK; + p_ie->ch_mode = *p_info & A2D_SBC_IE_CH_MD_MSK; + p_info++; + p_ie->block_len = *p_info & A2D_SBC_IE_BLOCKS_MSK; + p_ie->num_subbands = *p_info & A2D_SBC_IE_SUBBAND_MSK; + p_ie->alloc_mthd = *p_info & A2D_SBC_IE_ALLOC_MD_MSK; + p_info++; + p_ie->min_bitpool = *p_info++; + p_ie->max_bitpool = *p_info; + status = A2D_SUCCESS; + if (p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL ) { + status = A2D_BAD_MIN_BITPOOL; + } + + if (p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL || + p_ie->max_bitpool < p_ie->min_bitpool) { + status = A2D_BAD_MAX_BITPOOL; + } + + if (for_caps == FALSE) { + if (A2D_BitsSet(p_ie->samp_freq) != A2D_SET_ONE_BIT) { + status = A2D_BAD_SAMP_FREQ; + } + if (A2D_BitsSet(p_ie->ch_mode) != A2D_SET_ONE_BIT) { + status = A2D_BAD_CH_MODE; + } + if (A2D_BitsSet(p_ie->block_len) != A2D_SET_ONE_BIT) { + status = A2D_BAD_BLOCK_LEN; + } + if (A2D_BitsSet(p_ie->num_subbands) != A2D_SET_ONE_BIT) { + status = A2D_BAD_SUBBANDS; + } + if (A2D_BitsSet(p_ie->alloc_mthd) != A2D_SET_ONE_BIT) { + status = A2D_BAD_ALLOC_MTHD; + } + } + } + } + return status; +} + +/****************************************************************************** +** +** Function A2D_BldSbcMplHdr +** +** Description This function is called by an application to parse +** the SBC Media Payload header. +** Input Parameters: +** frag: 1, if fragmented. 0, otherwise. +** +** start: 1, if the starting packet of a fragmented frame. +** +** last: 1, if the last packet of a fragmented frame. +** +** num: If frag is 1, this is the number of remaining fragments +** (including this fragment) of this frame. +** If frag is 0, this is the number of frames in this packet. +** +** Output Parameters: +** p_dst: the resulting media payload header byte sequence. +** +** Returns void. +******************************************************************************/ +void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start, BOOLEAN last, UINT8 num) +{ + if (p_dst) { + *p_dst = 0; + if (frag) { + *p_dst |= A2D_SBC_HDR_F_MSK; + } + if (start) { + *p_dst |= A2D_SBC_HDR_S_MSK; + } + if (last) { + *p_dst |= A2D_SBC_HDR_L_MSK; + } + *p_dst |= (A2D_SBC_HDR_NUM_MSK & num); + } +} + +/****************************************************************************** +** +** Function A2D_ParsSbcMplHdr +** +** Description This function is called by an application to parse +** the SBC Media Payload header. +** Input Parameters: +** p_src: the byte sequence to parse.. +** +** Output Parameters: +** frag: 1, if fragmented. 0, otherwise. +** +** start: 1, if the starting packet of a fragmented frame. +** +** last: 1, if the last packet of a fragmented frame. +** +** num: If frag is 1, this is the number of remaining fragments +** (including this fragment) of this frame. +** If frag is 0, this is the number of frames in this packet. +** +** Returns void. +******************************************************************************/ +void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag, BOOLEAN *p_start, BOOLEAN *p_last, UINT8 *p_num) +{ + if (p_src && p_frag && p_start && p_last && p_num) { + *p_frag = (*p_src & A2D_SBC_HDR_F_MSK) ? TRUE : FALSE; + *p_start = (*p_src & A2D_SBC_HDR_S_MSK) ? TRUE : FALSE; + *p_last = (*p_src & A2D_SBC_HDR_L_MSK) ? TRUE : FALSE; + *p_num = (*p_src & A2D_SBC_HDR_NUM_MSK); + } +} + +#endif /* #if (defined(A2D_INCLUDED) && A2D_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/a2dp/include/a2d_int.h b/components/bt/bluedroid/stack/a2dp/include/a2d_int.h new file mode 100644 index 0000000000..d362f3f5b0 --- /dev/null +++ b/components/bt/bluedroid/stack/a2dp/include/a2d_int.h @@ -0,0 +1,81 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * 2DP internal header file + * + ******************************************************************************/ +#ifndef A2D_INT_H +#define A2D_INT_H + +#include "a2d_api.h" + +/***************************************************************************** +** Constants +*****************************************************************************/ +#define A2D_VERSION 0x0102 + +/* Number of attributes in A2D SDP record. */ +#define A2D_NUM_ATTR 6 + +/* Number of protocol elements in protocol element list. */ +#define A2D_NUM_PROTO_ELEMS 2 + +/***************************************************************************** +** Type definitions +*****************************************************************************/ + +/* Control block used by A2D_FindService(). */ +typedef struct { + tA2D_FIND_CBACK *p_cback; /* pointer to application callback */ + tSDP_DISCOVERY_DB *p_db; /* pointer to discovery database */ + UINT16 service_uuid; /* service UUID of search */ +} tA2D_FIND_CB; + +typedef struct { + tA2D_FIND_CB find; /* find service control block */ + UINT8 trace_level; + BOOLEAN use_desc; + UINT16 avdt_sdp_ver; /* AVDTP version */ +} tA2D_CB; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************************************************************** +** Main Control Block +*******************************************************************************/ +#if A2D_DYNAMIC_MEMORY == FALSE +extern tA2D_CB a2d_cb; +#else +extern tA2D_CB *a2d_cb_ptr; +#define a2d_cb (*a2d_cb_ptr) +#endif + +/* Used only for conformance testing */ +extern void a2d_set_avdt_sdp_ver (UINT16 avdt_sdp_ver); + +#ifdef __cplusplus +} +#endif + +#endif /* A2D_INT_H */ diff --git a/components/bt/bluedroid/stack/avct/avct_api.c b/components/bt/bluedroid/stack/avct/avct_api.c new file mode 100644 index 0000000000..15ae41b6ee --- /dev/null +++ b/components/bt/bluedroid/stack/avct/avct_api.c @@ -0,0 +1,442 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains API of the audio/video control transport protocol. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "gki.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#include "btm_api.h" +#include "avct_api.h" +#include "avct_int.h" + +#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) + +/* Control block for AVCT */ +#if AVCT_DYNAMIC_MEMORY == FALSE +tAVCT_CB avct_cb; +#endif + +/******************************************************************************* +** +** Function AVCT_Register +** +** Description This is the system level registration function for the +** AVCTP protocol. This function initializes AVCTP and +** prepares the protocol stack for its use. This function +** must be called once by the system or platform using AVCTP +** before the other functions of the API an be used. +** +** +** Returns void +** +*******************************************************************************/ +void AVCT_Register(UINT16 mtu, UINT16 mtu_br, UINT8 sec_mask) +{ + UNUSED(mtu_br); + + AVCT_TRACE_API("AVCT_Register"); + + /* register PSM with L2CAP */ + L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_appl); + + /* set security level */ + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0); + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0, 0); + + /* initialize AVCTP data structures */ + memset(&avct_cb, 0, sizeof(tAVCT_CB)); + +#if (AVCT_BROWSE_INCLUDED == TRUE) + /* Include the browsing channel which uses eFCR */ + L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO *) &avct_l2c_br_appl); + + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0); + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVCTP_BROWSE, sec_mask, AVCT_BR_PSM, 0, 0); + + if (mtu_br < AVCT_MIN_BROWSE_MTU) { + mtu_br = AVCT_MIN_BROWSE_MTU; + } + avct_cb.mtu_br = mtu_br; +#endif + +#if defined(AVCT_INITIAL_TRACE_LEVEL) + avct_cb.trace_level = AVCT_INITIAL_TRACE_LEVEL; +#else + avct_cb.trace_level = BT_TRACE_LEVEL_NONE; +#endif + + if (mtu < AVCT_MIN_CONTROL_MTU) { + mtu = AVCT_MIN_CONTROL_MTU; + } + /* store mtu */ + avct_cb.mtu = mtu; +} + +/******************************************************************************* +** +** Function AVCT_Deregister +** +** Description This function is called to deregister use AVCTP protocol. +** It is called when AVCTP is no longer being used by any +** application in the system. Before this function can be +** called, all connections must be removed with +** AVCT_RemoveConn(). +** +** +** Returns void +** +*******************************************************************************/ +void AVCT_Deregister(void) +{ + AVCT_TRACE_API("AVCT_Deregister"); + + /* deregister PSM with L2CAP */ + L2CA_Deregister(AVCT_PSM); +} + +/******************************************************************************* +** +** Function AVCT_CreateConn +** +** Description Create an AVCTP connection. There are two types of +** connections, initiator and acceptor, as determined by +** the p_cc->role parameter. When this function is called to +** create an initiator connection, an AVCTP connection to +** the peer device is initiated if one does not already exist. +** If an acceptor connection is created, the connection waits +** passively for an incoming AVCTP connection from a peer device. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVCT_CreateConn(UINT8 *p_handle, tAVCT_CC *p_cc, BD_ADDR peer_addr) +{ + UINT16 result = AVCT_SUCCESS; + tAVCT_CCB *p_ccb; + tAVCT_LCB *p_lcb; + + AVCT_TRACE_API("AVCT_CreateConn: %d, control:%d", p_cc->role, p_cc->control); + + /* Allocate ccb; if no ccbs, return failure */ + if ((p_ccb = avct_ccb_alloc(p_cc)) == NULL) { + result = AVCT_NO_RESOURCES; + } else { + /* get handle */ + *p_handle = avct_ccb_to_idx(p_ccb); + + /* if initiator connection */ + if (p_cc->role == AVCT_INT) { + /* find link; if none allocate a new one */ + if ((p_lcb = avct_lcb_by_bd(peer_addr)) == NULL) { + if ((p_lcb = avct_lcb_alloc(peer_addr)) == NULL) { + /* no link resources; free ccb as well */ + avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL); + result = AVCT_NO_RESOURCES; + } + } + /* check if PID already in use */ + else if (avct_lcb_has_pid(p_lcb, p_cc->pid)) { + avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL); + result = AVCT_PID_IN_USE; + } + + if (result == AVCT_SUCCESS) { + /* bind lcb to ccb */ + p_ccb->p_lcb = p_lcb; + AVCT_TRACE_DEBUG("ch_state: %d", p_lcb->ch_state); + avct_lcb_event(p_lcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb); + } + } + } + return result; +} + +/******************************************************************************* +** +** Function AVCT_RemoveConn +** +** Description Remove an AVCTP connection. This function is called when +** the application is no longer using a connection. If this +** is the last connection to a peer the L2CAP channel for AVCTP +** will be closed. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVCT_RemoveConn(UINT8 handle) +{ + UINT16 result = AVCT_SUCCESS; + tAVCT_CCB *p_ccb; + + AVCT_TRACE_API("AVCT_RemoveConn"); + + /* map handle to ccb */ + if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) { + result = AVCT_BAD_HANDLE; + } + /* if connection not bound to lcb, dealloc */ + else if (p_ccb->p_lcb == NULL) { + avct_ccb_dealloc(p_ccb, AVCT_NO_EVT, 0, NULL); + } + /* send unbind event to lcb */ + else { + avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb); + } + return result; +} + +/******************************************************************************* +** +** Function AVCT_CreateBrowse +** +** Description Create an AVCTP Browse channel. There are two types of +** connections, initiator and acceptor, as determined by +** the role parameter. When this function is called to +** create an initiator connection, the Browse channel to +** the peer device is initiated if one does not already exist. +** If an acceptor connection is created, the connection waits +** passively for an incoming AVCTP connection from a peer device. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVCT_CreateBrowse (UINT8 handle, UINT8 role) +{ +#if (AVCT_BROWSE_INCLUDED == TRUE) + UINT16 result = AVCT_SUCCESS; + tAVCT_CCB *p_ccb; + tAVCT_BCB *p_bcb; + int index; + + AVCT_TRACE_API("AVCT_CreateBrowse: %d", role); + + /* map handle to ccb */ + if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) { + return AVCT_BAD_HANDLE; + } else { + /* mark this CCB as supporting browsing channel */ + if ((p_ccb->allocated & AVCT_ALOC_BCB) == 0) { + p_ccb->allocated |= AVCT_ALOC_BCB; + } + } + + /* if initiator connection */ + if (role == AVCT_INT) { + /* the link control block must exist before this function is called as INT. */ + if ((p_ccb->p_lcb == NULL) || (p_ccb->p_lcb->allocated == 0)) { + result = AVCT_NOT_OPEN; + } else { + /* find link; if none allocate a new one */ + index = p_ccb->p_lcb->allocated; + if (index > AVCT_NUM_LINKS) { + result = AVCT_BAD_HANDLE; + } else { + p_bcb = &avct_cb.bcb[index - 1]; + p_bcb->allocated = index; + } + } + + if (result == AVCT_SUCCESS) { + /* bind bcb to ccb */ + p_ccb->p_bcb = p_bcb; + AVCT_TRACE_DEBUG("ch_state: %d", p_bcb->ch_state); + avct_bcb_event(p_bcb, AVCT_LCB_UL_BIND_EVT, (tAVCT_LCB_EVT *) &p_ccb); + } + } + + return result; +#else + UNUSED(handle); + UNUSED(role); + return AVCT_NO_RESOURCES; +#endif +} + +/******************************************************************************* +** +** Function AVCT_RemoveBrowse +** +** Description Remove an AVCTP Browse channel. This function is called when +** the application is no longer using a connection. If this +** is the last connection to a peer the L2CAP channel for AVCTP +** will be closed. +** +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVCT_RemoveBrowse (UINT8 handle) +{ +#if (AVCT_BROWSE_INCLUDED == TRUE) + UINT16 result = AVCT_SUCCESS; + tAVCT_CCB *p_ccb; + + AVCT_TRACE_API("AVCT_RemoveBrowse"); + + /* map handle to ccb */ + if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) { + result = AVCT_BAD_HANDLE; + } else if (p_ccb->p_bcb != NULL) + /* send unbind event to bcb */ + { + avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb); + } + return result; +#else + UNUSED(handle); + return AVCT_NO_RESOURCES; +#endif +} + +/******************************************************************************* +** +** Function AVCT_GetBrowseMtu +** +** Description Get the peer_mtu for the AVCTP Browse channel of the given +** connection. +** +** Returns the peer browsing channel MTU. +** +*******************************************************************************/ +UINT16 AVCT_GetBrowseMtu (UINT8 handle) +{ + UINT16 peer_mtu = AVCT_MIN_BROWSE_MTU; +#if (AVCT_BROWSE_INCLUDED == TRUE) + tAVCT_CCB *p_ccb; + + if ((p_ccb = avct_ccb_by_idx(handle)) != NULL && p_ccb->p_bcb != NULL) { + peer_mtu = p_ccb->p_bcb->peer_mtu; + } +#else + UNUSED(handle); +#endif + return peer_mtu; +} + +/******************************************************************************* +** +** Function AVCT_GetPeerMtu +** +** Description Get the peer_mtu for the AVCTP channel of the given +** connection. +** +** Returns the peer MTU size. +** +*******************************************************************************/ +UINT16 AVCT_GetPeerMtu (UINT8 handle) +{ + UINT16 peer_mtu = L2CAP_DEFAULT_MTU; + tAVCT_CCB *p_ccb; + + /* map handle to ccb */ + if ((p_ccb = avct_ccb_by_idx(handle)) != NULL) { + if (p_ccb->p_lcb) { + peer_mtu = p_ccb->p_lcb->peer_mtu; + } + } + + return peer_mtu; +} + +/******************************************************************************* +** +** Function AVCT_MsgReq +** +** Description Send an AVCTP message to a peer device. In calling +** AVCT_MsgReq(), the application should keep track of the +** congestion state of AVCTP as communicated with events +** AVCT_CONG_IND_EVT and AVCT_UNCONG_IND_EVT. If the +** application calls AVCT_MsgReq() when AVCTP is congested +** the message may be discarded. The application may make its +** first call to AVCT_MsgReq() after it receives an +** AVCT_CONNECT_CFM_EVT or AVCT_CONNECT_IND_EVT on control channel or +** AVCT_BROWSE_CONN_CFM_EVT or AVCT_BROWSE_CONN_IND_EVT on browsing channel. +** +** p_msg->layer_specific must be set to +** AVCT_DATA_CTRL for control channel traffic; +** AVCT_DATA_BROWSE for for browse channel traffic. +** +** Returns AVCT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVCT_MsgReq(UINT8 handle, UINT8 label, UINT8 cr, BT_HDR *p_msg) +{ + UINT16 result = AVCT_SUCCESS; + tAVCT_CCB *p_ccb; + tAVCT_UL_MSG ul_msg; + + AVCT_TRACE_API("AVCT_MsgReq"); + + /* verify p_msg parameter */ + if (p_msg == NULL) { + return AVCT_NO_RESOURCES; + } + AVCT_TRACE_API("len: %d", p_msg->len); + + /* map handle to ccb */ + if ((p_ccb = avct_ccb_by_idx(handle)) == NULL) { + result = AVCT_BAD_HANDLE; + GKI_freebuf(p_msg); + } + /* verify channel is bound to link */ + else if (p_ccb->p_lcb == NULL) { + result = AVCT_NOT_OPEN; + GKI_freebuf(p_msg); + } + + if (result == AVCT_SUCCESS) { + ul_msg.p_buf = p_msg; + ul_msg.p_ccb = p_ccb; + ul_msg.label = label; + ul_msg.cr = cr; + +#if (AVCT_BROWSE_INCLUDED == TRUE) + /* send msg event to bcb */ + if (p_msg->layer_specific == AVCT_DATA_BROWSE) { + if (p_ccb->p_bcb == NULL && (p_ccb->allocated & AVCT_ALOC_BCB) == 0) { + /* BCB channel is not open and not allocated */ + result = AVCT_BAD_HANDLE; + GKI_freebuf(p_msg); + } else { + p_ccb->p_bcb = avct_bcb_by_lcb(p_ccb->p_lcb); + avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg); + } + } + /* send msg event to lcb */ + else +#endif + { + avct_lcb_event(p_ccb->p_lcb, AVCT_LCB_UL_MSG_EVT, (tAVCT_LCB_EVT *) &ul_msg); + } + } + return result; +} + +#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avct/avct_ccb.c b/components/bt/bluedroid/stack/avct/avct_ccb.c new file mode 100644 index 0000000000..06ff5014d0 --- /dev/null +++ b/components/bt/bluedroid/stack/avct/avct_ccb.c @@ -0,0 +1,145 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains functions which operate on the AVCTP connection + * control block. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "avct_api.h" +#include "avct_int.h" + +#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function avct_ccb_alloc +** +** Description Allocate a connection control block; copy parameters to ccb. +** +** +** Returns pointer to the ccb, or NULL if none could be allocated. +** +*******************************************************************************/ +tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (!p_ccb->allocated) { + p_ccb->allocated = AVCT_ALOC_LCB; + memcpy(&p_ccb->cc, p_cc, sizeof(tAVCT_CC)); + AVCT_TRACE_DEBUG("avct_ccb_alloc %d", i); + break; + } + } + + if (i == AVCT_NUM_CONN) { + /* out of ccbs */ + p_ccb = NULL; + AVCT_TRACE_WARNING("Out of ccbs"); + } + return p_ccb; +} + +/******************************************************************************* +** +** Function avct_ccb_dealloc +** +** Description Deallocate a connection control block and call application +** callback. +** +** +** Returns void. +** +*******************************************************************************/ +void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr) +{ + tAVCT_CTRL_CBACK *p_cback = p_ccb->cc.p_ctrl_cback; + + AVCT_TRACE_DEBUG("avct_ccb_dealloc %d", avct_ccb_to_idx(p_ccb)); +#if (AVCT_BROWSE_INCLUDED == TRUE) + if (p_ccb->p_bcb == NULL) { + memset(p_ccb, 0, sizeof(tAVCT_CCB)); + } else { + /* control channel is down, but the browsing channel is still connected 0 disconnect it now */ + avct_bcb_event(p_ccb->p_bcb, AVCT_LCB_UL_UNBIND_EVT, (tAVCT_LCB_EVT *) &p_ccb); + p_ccb->p_lcb = NULL; + } +#else + memset(p_ccb, 0, sizeof(tAVCT_CCB)); +#endif + + if (event != AVCT_NO_EVT) { + (*p_cback)(avct_ccb_to_idx(p_ccb), event, result, bd_addr); + } +} + +/******************************************************************************* +** +** Function avct_ccb_to_idx +** +** Description Given a pointer to an ccb, return its index. +** +** +** Returns Index of ccb. +** +*******************************************************************************/ +UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb) +{ + /* use array arithmetic to determine index */ + return (UINT8) (p_ccb - avct_cb.ccb); +} + +/******************************************************************************* +** +** Function avct_ccb_by_idx +** +** Description Return ccb pointer based on ccb index (or handle). +** +** +** Returns pointer to the ccb, or NULL if none found. +** +*******************************************************************************/ +tAVCT_CCB *avct_ccb_by_idx(UINT8 idx) +{ + tAVCT_CCB *p_ccb; + + /* verify index */ + if (idx < AVCT_NUM_CONN) { + p_ccb = &avct_cb.ccb[idx]; + + /* verify ccb is allocated */ + if (!p_ccb->allocated) { + p_ccb = NULL; + AVCT_TRACE_WARNING("ccb %d not allocated", idx); + } + } else { + p_ccb = NULL; + AVCT_TRACE_WARNING("No ccb for idx %d", idx); + } + return p_ccb; +} + +#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avct/avct_l2c.c b/components/bt/bluedroid/stack/avct/avct_l2c.c new file mode 100644 index 0000000000..9de15da173 --- /dev/null +++ b/components/bt/bluedroid/stack/avct/avct_l2c.c @@ -0,0 +1,405 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This AVCTP module interfaces to L2CAP + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avct_api.h" +#include "avct_int.h" +#include "l2c_api.h" +#include "l2cdefs.h" + +#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) + +/* Configuration flags. */ +#define AVCT_L2C_CFG_IND_DONE (1<<0) +#define AVCT_L2C_CFG_CFM_DONE (1<<1) + +/* callback function declarations */ +void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); +void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result); +void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed); +void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result); +void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested); +void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf); + +/* L2CAP callback function structure */ +const tL2CAP_APPL_INFO avct_l2c_appl = { + avct_l2c_connect_ind_cback, + avct_l2c_connect_cfm_cback, + NULL, + avct_l2c_config_ind_cback, + avct_l2c_config_cfm_cback, + avct_l2c_disconnect_ind_cback, + avct_l2c_disconnect_cfm_cback, + NULL, + avct_l2c_data_ind_cback, + avct_l2c_congestion_ind_cback, + NULL /* tL2CA_TX_COMPLETE_CB */ +}; + +/******************************************************************************* +** +** Function avct_l2c_is_passive +** +** Description check is the CCB associated with the given LCB was created +** as passive +** +** Returns TRUE, if the given LCB is created as AVCT_PASSIVE +** +*******************************************************************************/ +static BOOLEAN avct_l2c_is_passive (tAVCT_LCB *p_lcb) +{ + BOOLEAN is_passive = FALSE; + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { + AVCT_TRACE_DEBUG("avct_l2c_is_ct control:x%x", p_ccb->cc.control); + if (p_ccb->cc.control & AVCT_PASSIVE) { + is_passive = TRUE; + break; + } + } + } + return is_passive; +} + +/******************************************************************************* +** +** Function avct_l2c_connect_ind_cback +** +** Description This is the L2CAP connect indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id) +{ + tAVCT_LCB *p_lcb; + UINT16 result = L2CAP_CONN_OK; + tL2CAP_CFG_INFO cfg; + UNUSED(psm); + + /* do we already have a channel for this peer? */ + if ((p_lcb = avct_lcb_by_bd(bd_addr)) == NULL) { + /* no, allocate lcb */ + if ((p_lcb = avct_lcb_alloc(bd_addr)) == NULL) { + /* no ccb available, reject L2CAP connection */ + result = L2CAP_CONN_NO_RESOURCES; + } + } + /* else we already have a channel for this peer */ + else { + if (!avct_l2c_is_passive (p_lcb) || (p_lcb->ch_state == AVCT_CH_OPEN)) { + /* this LCB included CT role - reject */ + result = L2CAP_CONN_NO_RESOURCES; + } else { + /* TG role only - accept the connection from CT. move the channel ID to the conflict list */ + p_lcb->conflict_lcid = p_lcb->ch_lcid; + AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback conflict_lcid:0x%x", p_lcb->conflict_lcid); + } + } + + if (p_lcb) { + AVCT_TRACE_DEBUG("avct_l2c_connect_ind_cback: 0x%x, res: %d, ch_state: %d", + lcid, result, p_lcb->ch_state); + } + /* Send L2CAP connect rsp */ + L2CA_ConnectRsp(bd_addr, id, lcid, result, 0); + + /* if result ok, proceed with connection */ + if (result == L2CAP_CONN_OK) { + /* store LCID */ + p_lcb->ch_lcid = lcid; + + /* transition to configuration state */ + p_lcb->ch_state = AVCT_CH_CFG; + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = avct_cb.mtu; + L2CA_ConfigReq(lcid, &cfg); + AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req"); + } + +#if (BT_USE_TRACES == TRUE) + if (p_lcb) { + AVCT_TRACE_DEBUG("ch_state cni: %d ", p_lcb->ch_state); + } +#endif +} + +/******************************************************************************* +** +** Function avct_l2c_connect_cfm_cback +** +** Description This is the L2CAP connect confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result) +{ + tAVCT_LCB *p_lcb; + tL2CAP_CFG_INFO cfg; + + /* look up lcb for this channel */ + if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) { + AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback lcid:0x%x result: %d ch_state: %d, conflict_lcid:0x%x", + lcid, result, p_lcb->ch_state, p_lcb->conflict_lcid); + /* if in correct state */ + if (p_lcb->ch_state == AVCT_CH_CONN) { + /* if result successful */ + if (result == L2CAP_CONN_OK) { + /* set channel state */ + p_lcb->ch_state = AVCT_CH_CFG; + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = avct_cb.mtu; + L2CA_ConfigReq(lcid, &cfg); + AVCT_TRACE_DEBUG("avct_l2c snd Cfg Req"); + } + /* else failure */ + else { + AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback conflict_lcid:0x%x", p_lcb->conflict_lcid); + if (p_lcb->conflict_lcid == lcid) { + p_lcb->conflict_lcid = 0; + } else { + avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result); + } + } + } else if (p_lcb->conflict_lcid == lcid) { + /* we must be in AVCT_CH_CFG state for the ch_lcid channel */ + AVCT_TRACE_DEBUG("avct_l2c_connect_cfm_cback ch_state: %d, conflict_lcid:0x%x", p_lcb->ch_state, p_lcb->conflict_lcid); + if (result == L2CAP_CONN_OK) { + /* just in case the peer also accepts our connection - Send L2CAP disconnect req */ + L2CA_DisconnectReq(lcid); + } + p_lcb->conflict_lcid = 0; + } + AVCT_TRACE_DEBUG("ch_state cnc: %d ", p_lcb->ch_state); + } +} + +/******************************************************************************* +** +** Function avct_l2c_config_cfm_cback +** +** Description This is the L2CAP config confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tAVCT_LCB *p_lcb; + + /* look up lcb for this channel */ + if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) { + AVCT_TRACE_DEBUG("avct_l2c_config_cfm_cback: 0x%x, ch_state: %d, res: %d", + lcid, p_lcb->ch_state, p_cfg->result); + /* if in correct state */ + if (p_lcb->ch_state == AVCT_CH_CFG) { + /* if result successful */ + if (p_cfg->result == L2CAP_CFG_OK) { + /* update flags */ + p_lcb->ch_flags |= AVCT_L2C_CFG_CFM_DONE; + + /* if configuration complete */ + if (p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) { + p_lcb->ch_state = AVCT_CH_OPEN; + avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL); + } + } + /* else failure */ + else { + AVCT_TRACE_DEBUG("ERROR avct_l2c_config_cfm_cback L2CA_DisconnectReq %d ", p_lcb->ch_state); + /* store result value */ + p_lcb->ch_result = p_cfg->result; + + /* Send L2CAP disconnect req */ + L2CA_DisconnectReq(lcid); + } + } + AVCT_TRACE_DEBUG("ch_state cfc: %d ", p_lcb->ch_state); + } +} + +/******************************************************************************* +** +** Function avct_l2c_config_ind_cback +** +** Description This is the L2CAP config indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tAVCT_LCB *p_lcb; + + /* look up lcb for this channel */ + if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) { + AVCT_TRACE_DEBUG("avct_l2c_config_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state); + /* store the mtu in tbl */ + if (p_cfg->mtu_present) { + p_lcb->peer_mtu = p_cfg->mtu; + } else { + p_lcb->peer_mtu = L2CAP_DEFAULT_MTU; + } + + /* send L2CAP configure response */ + memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO)); + p_cfg->result = L2CAP_CFG_OK; + L2CA_ConfigRsp(lcid, p_cfg); + + /* if first config ind */ + if ((p_lcb->ch_flags & AVCT_L2C_CFG_IND_DONE) == 0) { + /* update flags */ + p_lcb->ch_flags |= AVCT_L2C_CFG_IND_DONE; + + /* if configuration complete */ + if (p_lcb->ch_flags & AVCT_L2C_CFG_CFM_DONE) { + p_lcb->ch_state = AVCT_CH_OPEN; + avct_lcb_event(p_lcb, AVCT_LCB_LL_OPEN_EVT, NULL); + } + } + AVCT_TRACE_DEBUG("ch_state cfi: %d ", p_lcb->ch_state); + } +} + +/******************************************************************************* +** +** Function avct_l2c_disconnect_ind_cback +** +** Description This is the L2CAP disconnect indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed) +{ + tAVCT_LCB *p_lcb; + UINT16 result = AVCT_RESULT_FAIL; + + /* look up lcb for this channel */ + if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) { + AVCT_TRACE_DEBUG("avct_l2c_disconnect_ind_cback: 0x%x, ch_state: %d", lcid, p_lcb->ch_state); + if (ack_needed) { + /* send L2CAP disconnect response */ + L2CA_DisconnectRsp(lcid); + } + + avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result); + AVCT_TRACE_DEBUG("ch_state di: %d ", p_lcb->ch_state); + } +} + +/******************************************************************************* +** +** Function avct_l2c_disconnect_cfm_cback +** +** Description This is the L2CAP disconnect confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result) +{ + tAVCT_LCB *p_lcb; + UINT16 res; + + /* look up lcb for this channel */ + if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) { + AVCT_TRACE_DEBUG("avct_l2c_disconnect_cfm_cback: 0x%x, ch_state: %d, res: %d", + lcid, p_lcb->ch_state, result); + /* result value may be previously stored */ + res = (p_lcb->ch_result != 0) ? p_lcb->ch_result : result; + p_lcb->ch_result = 0; + + avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &res); + AVCT_TRACE_DEBUG("ch_state dc: %d ", p_lcb->ch_state); + } +} + +/******************************************************************************* +** +** Function avct_l2c_congestion_ind_cback +** +** Description This is the L2CAP congestion indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested) +{ + tAVCT_LCB *p_lcb; + + AVCT_TRACE_DEBUG("avct_l2c_congestion_ind_cback: 0x%x", lcid); + /* look up lcb for this channel */ + if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) { + avct_lcb_event(p_lcb, AVCT_LCB_LL_CONG_EVT, (tAVCT_LCB_EVT *) &is_congested); + } +} + +/******************************************************************************* +** +** Function avct_l2c_data_ind_cback +** +** Description This is the L2CAP data indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avct_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf) +{ + tAVCT_LCB *p_lcb; + + AVCT_TRACE_DEBUG("avct_l2c_data_ind_cback: 0x%x", lcid); + /* look up lcb for this channel */ + if ((p_lcb = avct_lcb_by_lcid(lcid)) != NULL) { + avct_lcb_event(p_lcb, AVCT_LCB_LL_MSG_EVT, (tAVCT_LCB_EVT *) &p_buf); + } else { /* prevent buffer leak */ + AVCT_TRACE_WARNING("ERROR -> avct_l2c_data_ind_cback drop buffer"); + GKI_freebuf(p_buf); + } +} + +#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avct/avct_lcb.c b/components/bt/bluedroid/stack/avct/avct_lcb.c new file mode 100644 index 0000000000..008fa8ff56 --- /dev/null +++ b/components/bt/bluedroid/stack/avct/avct_lcb.c @@ -0,0 +1,449 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains the link control state machine and functions which + * operate on the link control block. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avct_api.h" +#include "avct_int.h" +#include "gki.h" + +#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) + +/***************************************************************************** +** state machine constants and types +*****************************************************************************/ + +#if BT_TRACE_VERBOSE == TRUE + +/* verbose state strings for trace */ +const char *const avct_lcb_st_str[] = { + "LCB_IDLE_ST", + "LCB_OPENING_ST", + "LCB_OPEN_ST", + "LCB_CLOSING_ST" +}; + +/* verbose event strings for trace */ +const char *const avct_lcb_evt_str[] = { + "UL_BIND_EVT", + "UL_UNBIND_EVT", + "UL_MSG_EVT", + "INT_CLOSE_EVT", + "LL_OPEN_EVT", + "LL_CLOSE_EVT", + "LL_MSG_EVT", + "LL_CONG_EVT" +}; + +#endif + +/* lcb state machine states */ +enum { + AVCT_LCB_IDLE_ST, + AVCT_LCB_OPENING_ST, + AVCT_LCB_OPEN_ST, + AVCT_LCB_CLOSING_ST +}; + +/* state machine action enumeration list */ +enum { + AVCT_LCB_CHNL_OPEN, + AVCT_LCB_CHNL_DISC, + AVCT_LCB_SEND_MSG, + AVCT_LCB_OPEN_IND, + AVCT_LCB_OPEN_FAIL, + AVCT_LCB_CLOSE_IND, + AVCT_LCB_CLOSE_CFM, + AVCT_LCB_MSG_IND, + AVCT_LCB_CONG_IND, + AVCT_LCB_BIND_CONN, + AVCT_LCB_BIND_FAIL, + AVCT_LCB_UNBIND_DISC, + AVCT_LCB_CHK_DISC, + AVCT_LCB_DISCARD_MSG, + AVCT_LCB_DEALLOC, + AVCT_LCB_FREE_MSG_IND, + AVCT_LCB_NUM_ACTIONS +}; + +#define AVCT_LCB_IGNORE AVCT_LCB_NUM_ACTIONS + +/* type for action functions */ +typedef void (*tAVCT_LCB_ACTION)(tAVCT_LCB *p_ccb, tAVCT_LCB_EVT *p_data); + +/* action function list */ +const tAVCT_LCB_ACTION avct_lcb_action[] = { + avct_lcb_chnl_open, + avct_lcb_chnl_disc, + avct_lcb_send_msg, + avct_lcb_open_ind, + avct_lcb_open_fail, + avct_lcb_close_ind, + avct_lcb_close_cfm, + avct_lcb_msg_ind, + avct_lcb_cong_ind, + avct_lcb_bind_conn, + avct_lcb_bind_fail, + avct_lcb_unbind_disc, + avct_lcb_chk_disc, + avct_lcb_discard_msg, + avct_lcb_dealloc, + avct_lcb_free_msg_ind +}; + +/* state table information */ +#define AVCT_LCB_ACTIONS 2 /* number of actions */ +#define AVCT_LCB_NEXT_STATE 2 /* position of next state */ +#define AVCT_LCB_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for idle state */ +const UINT8 avct_lcb_st_idle[][AVCT_LCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* UL_BIND_EVT */ {AVCT_LCB_CHNL_OPEN, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}, + /* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}, + /* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}, + /* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}, + /* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}, + /* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST}, + /* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST}, + /* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_IDLE_ST} +}; + +/* state table for opening state */ +const UINT8 avct_lcb_st_opening[][AVCT_LCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* UL_BIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}, + /* UL_UNBIND_EVT */ {AVCT_LCB_UNBIND_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}, + /* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}, + /* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* LL_OPEN_EVT */ {AVCT_LCB_OPEN_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}, + /* LL_CLOSE_EVT */ {AVCT_LCB_OPEN_FAIL, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST}, + /* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST}, + /* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPENING_ST} +}; + +/* state table for open state */ +const UINT8 avct_lcb_st_open[][AVCT_LCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* UL_BIND_EVT */ {AVCT_LCB_BIND_CONN, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}, + /* UL_UNBIND_EVT */ {AVCT_LCB_CHK_DISC, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}, + /* UL_MSG_EVT */ {AVCT_LCB_SEND_MSG, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}, + /* INT_CLOSE_EVT */ {AVCT_LCB_CHNL_DISC, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}, + /* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_IND, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST}, + /* LL_MSG_EVT */ {AVCT_LCB_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST}, + /* LL_CONG_EVT */ {AVCT_LCB_CONG_IND, AVCT_LCB_IGNORE, AVCT_LCB_OPEN_ST} +}; + +/* state table for closing state */ +const UINT8 avct_lcb_st_closing[][AVCT_LCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* UL_BIND_EVT */ {AVCT_LCB_BIND_FAIL, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* UL_UNBIND_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* UL_MSG_EVT */ {AVCT_LCB_DISCARD_MSG, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* INT_CLOSE_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* LL_OPEN_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* LL_CLOSE_EVT */ {AVCT_LCB_CLOSE_CFM, AVCT_LCB_DEALLOC, AVCT_LCB_IDLE_ST}, + /* LL_MSG_EVT */ {AVCT_LCB_FREE_MSG_IND, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST}, + /* LL_CONG_EVT */ {AVCT_LCB_IGNORE, AVCT_LCB_IGNORE, AVCT_LCB_CLOSING_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tAVCT_LCB_ST_TBL)[AVCT_LCB_NUM_COLS]; + +/* state table */ +const tAVCT_LCB_ST_TBL avct_lcb_st_tbl[] = { + avct_lcb_st_idle, + avct_lcb_st_opening, + avct_lcb_st_open, + avct_lcb_st_closing +}; + +/******************************************************************************* +** +** Function avct_lcb_event +** +** Description State machine event handling function for lcb +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data) +{ + tAVCT_LCB_ST_TBL state_table; + UINT8 action; + int i; + +#if BT_TRACE_VERBOSE == TRUE + AVCT_TRACE_EVENT("LCB lcb=%d event=%s state=%s", p_lcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_lcb->state]); +#else + AVCT_TRACE_EVENT("LCB lcb=%d event=%d state=%d", p_lcb->allocated, event, p_lcb->state); +#endif + + /* look up the state table for the current state */ + state_table = avct_lcb_st_tbl[p_lcb->state]; + + /* set next state */ + p_lcb->state = state_table[event][AVCT_LCB_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < AVCT_LCB_ACTIONS; i++) { + if ((action = state_table[event][i]) != AVCT_LCB_IGNORE) { + (*avct_lcb_action[action])(p_lcb, p_data); + } else { + break; + } + } +} + +/******************************************************************************* +** +** Function avct_bcb_event +** +** Description State machine event handling function for lcb +** +** +** Returns Nothing. +** +*******************************************************************************/ +#if (AVCT_BROWSE_INCLUDED == TRUE) +void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data) +{ + tAVCT_LCB_ST_TBL state_table; + UINT8 action; + int i; + +#if BT_TRACE_VERBOSE == TRUE + AVCT_TRACE_EVENT("BCB lcb=%d event=%s state=%s", p_bcb->allocated, avct_lcb_evt_str[event], avct_lcb_st_str[p_bcb->state]); +#else + AVCT_TRACE_EVENT("BCB lcb=%d event=%d state=%d", p_bcb->allocated, event, p_bcb->state); +#endif + + /* look up the state table for the current state */ + state_table = avct_lcb_st_tbl[p_bcb->state]; + + /* set next state */ + p_bcb->state = state_table[event][AVCT_LCB_NEXT_STATE]; + + /* execute action functions */ + for (i = 0; i < AVCT_LCB_ACTIONS; i++) { + if ((action = state_table[event][i]) != AVCT_LCB_IGNORE) { + (*avct_bcb_action[action])(p_bcb, p_data); + } else { + break; + } + } +} +#endif + +/******************************************************************************* +** +** Function avct_lcb_by_bd +** +** Description This lookup function finds the lcb for a BD address. +** +** +** Returns pointer to the lcb, or NULL if none found. +** +*******************************************************************************/ +tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr) +{ + tAVCT_LCB *p_lcb = &avct_cb.lcb[0]; + int i; + + for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) { + /* if allocated lcb has matching lcb */ + if (p_lcb->allocated && (!memcmp(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN))) { + break; + } + } + + if (i == AVCT_NUM_LINKS) { + /* if no lcb found */ + p_lcb = NULL; + + AVCT_TRACE_DEBUG("No lcb for addr %02x-%02x-%02x-%02x-%02x-%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + } + return p_lcb; +} + +/******************************************************************************* +** +** Function avct_lcb_alloc +** +** Description Allocate a link control block. +** +** +** Returns pointer to the lcb, or NULL if none could be allocated. +** +*******************************************************************************/ +tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr) +{ + tAVCT_LCB *p_lcb = &avct_cb.lcb[0]; + int i; + + for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) { + if (!p_lcb->allocated) { + p_lcb->allocated = (UINT8)(i + 1); + memcpy(p_lcb->peer_addr, bd_addr, BD_ADDR_LEN); + AVCT_TRACE_DEBUG("avct_lcb_alloc %d", p_lcb->allocated); + break; + } + } + + if (i == AVCT_NUM_LINKS) { + /* out of lcbs */ + p_lcb = NULL; + AVCT_TRACE_WARNING("Out of lcbs"); + } + return p_lcb; +} + +/******************************************************************************* +** +** Function avct_lcb_dealloc +** +** Description Deallocate a link control block. +** +** +** Returns void. +** +*******************************************************************************/ +void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + BOOLEAN found = FALSE; + int i; + UNUSED(p_data); + + AVCT_TRACE_DEBUG("avct_lcb_dealloc %d", p_lcb->allocated); + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + /* if ccb allocated and */ + if (p_ccb->allocated) { + if (p_ccb->p_lcb == p_lcb) { + AVCT_TRACE_DEBUG("avct_lcb_dealloc used by ccb: %d", i); + found = TRUE; + break; + } + } + } + + if (!found) { + AVCT_TRACE_DEBUG("avct_lcb_dealloc now"); + + /* clear reassembled msg buffer if in use */ + if (p_lcb->p_rx_msg != NULL) { + GKI_freebuf(p_lcb->p_rx_msg); + } + memset(p_lcb, 0, sizeof(tAVCT_LCB)); + } +} + +/******************************************************************************* +** +** Function avct_lcb_by_lcid +** +** Description Find the LCB associated with the L2CAP LCID +** +** +** Returns pointer to the lcb, or NULL if none found. +** +*******************************************************************************/ +tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid) +{ + tAVCT_LCB *p_lcb = &avct_cb.lcb[0]; + int i; + + for (i = 0; i < AVCT_NUM_LINKS; i++, p_lcb++) { + if (p_lcb->allocated && ((p_lcb->ch_lcid == lcid) || (p_lcb->conflict_lcid == lcid))) { + break; + } + } + + if (i == AVCT_NUM_LINKS) { + /* out of lcbs */ + p_lcb = NULL; + AVCT_TRACE_WARNING("No lcb for lcid %x", lcid); + } + + return p_lcb; +} + +/******************************************************************************* +** +** Function avct_lcb_has_pid +** +** Description See if any ccbs on this lcb have a particular pid. +** +** +** Returns Pointer to CCB if PID found, NULL otherwise. +** +*******************************************************************************/ +tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb->cc.pid == pid)) { + return p_ccb; + } + } + return NULL; +} + +/******************************************************************************* +** +** Function avct_lcb_last_ccb +** +** Description See if given ccb is only one on the lcb. +** +** +** Returns TRUE if ccb is last, FALSE otherwise. +** +*******************************************************************************/ +BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + + AVCT_TRACE_WARNING("avct_lcb_last_ccb"); + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + AVCT_TRACE_WARNING("%x: aloc:%d, lcb:%p/%p, ccb:%p/%p", + i, p_ccb->allocated, p_ccb->p_lcb, p_lcb, p_ccb, p_ccb_last); + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb) && (p_ccb != p_ccb_last)) { + return FALSE; + } + } + return TRUE; +} + + +#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avct/avct_lcb_act.c b/components/bt/bluedroid/stack/avct/avct_lcb_act.c new file mode 100644 index 0000000000..164e630991 --- /dev/null +++ b/components/bt/bluedroid/stack/avct/avct_lcb_act.c @@ -0,0 +1,670 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains action functions of the link control state machine. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avct_api.h" +#include "avct_int.h" +#include "gki.h" +#include "btm_api.h" + +#if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) + +/* packet header length lookup table */ +const UINT8 avct_lcb_pkt_type_len[] = { + AVCT_HDR_LEN_SINGLE, + AVCT_HDR_LEN_START, + AVCT_HDR_LEN_CONT, + AVCT_HDR_LEN_END +}; + +/******************************************************************************* +** +** Function avct_lcb_msg_asmbl +** +** Description Reassemble incoming message. +** +** +** Returns Pointer to reassembled message; NULL if no message +** available. +** +*******************************************************************************/ +static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf) +{ + UINT8 *p; + UINT8 pkt_type; + BT_HDR *p_ret; + UINT16 buf_len; + + /* parse the message header */ + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + AVCT_PRS_PKT_TYPE(p, pkt_type); + + /* quick sanity check on length */ + if (p_buf->len < avct_lcb_pkt_type_len[pkt_type]) { + GKI_freebuf(p_buf); + AVCT_TRACE_WARNING("Bad length during reassembly"); + p_ret = NULL; + } + /* single packet */ + else if (pkt_type == AVCT_PKT_TYPE_SINGLE) { + /* if reassembly in progress drop message and process new single */ + if (p_lcb->p_rx_msg != NULL) { + GKI_freebuf(p_lcb->p_rx_msg); + p_lcb->p_rx_msg = NULL; + AVCT_TRACE_WARNING("Got single during reassembly"); + } + p_ret = p_buf; + } + /* start packet */ + else if (pkt_type == AVCT_PKT_TYPE_START) { + /* if reassembly in progress drop message and process new start */ + if (p_lcb->p_rx_msg != NULL) { + GKI_freebuf(p_lcb->p_rx_msg); + AVCT_TRACE_WARNING("Got start during reassembly"); + } + /* Allocate bigger buffer for reassembly. As lower layers are + * not aware of possible packet size after reassembly they + * would have allocated smaller buffer. + */ + p_lcb->p_rx_msg = (BT_HDR *)GKI_getbuf(GKI_MAX_BUF_SIZE); + if (p_lcb->p_rx_msg == NULL) { + AVCT_TRACE_ERROR ("Cannot alloc buffer for reassembly !!"); + GKI_freebuf(p_buf); + } else { + memcpy (p_lcb->p_rx_msg, p_buf, + sizeof(BT_HDR) + p_buf->offset + p_buf->len); + /* Free original buffer */ + GKI_freebuf(p_buf); + + /* update p to point to new buffer */ + p = (UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset; + + /* copy first header byte over nosp */ + *(p + 1) = *p; + + /* set offset to point to where to copy next */ + p_lcb->p_rx_msg->offset += p_lcb->p_rx_msg->len; + + /* adjust length for packet header */ + p_lcb->p_rx_msg->len -= 1; + } + p_ret = NULL; + } + /* continue or end */ + else { + /* if no reassembly in progress drop message */ + if (p_lcb->p_rx_msg == NULL) { + GKI_freebuf(p_buf); + AVCT_TRACE_WARNING("Pkt type=%d out of order", pkt_type); + p_ret = NULL; + } else { + /* get size of buffer holding assembled message */ + buf_len = GKI_get_buf_size(p_lcb->p_rx_msg) - sizeof(BT_HDR); + + /* adjust offset and len of fragment for header byte */ + p_buf->offset += AVCT_HDR_LEN_CONT; + p_buf->len -= AVCT_HDR_LEN_CONT; + + /* verify length */ + if ((p_lcb->p_rx_msg->offset + p_buf->len) > buf_len) { + /* won't fit; free everything */ + GKI_freebuf(p_lcb->p_rx_msg); + p_lcb->p_rx_msg = NULL; + GKI_freebuf(p_buf); + p_ret = NULL; + AVCT_TRACE_WARNING("Fragmented message to big!"); + } else { + /* copy contents of p_buf to p_rx_msg */ + memcpy((UINT8 *)(p_lcb->p_rx_msg + 1) + p_lcb->p_rx_msg->offset, + (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len); + + if (pkt_type == AVCT_PKT_TYPE_END) { + p_lcb->p_rx_msg->offset -= p_lcb->p_rx_msg->len; + p_lcb->p_rx_msg->len += p_buf->len; + p_ret = p_lcb->p_rx_msg; + p_lcb->p_rx_msg = NULL; + } else { + p_lcb->p_rx_msg->offset += p_buf->len; + p_lcb->p_rx_msg->len += p_buf->len; + p_ret = NULL; + } + GKI_freebuf(p_buf); + } + } + } + return p_ret; +} + + +/******************************************************************************* +** +** Function avct_lcb_chnl_open +** +** Description Open L2CAP channel to peer +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UINT16 result = AVCT_RESULT_FAIL; + UNUSED(p_data); + + BTM_SetOutService(p_lcb->peer_addr, BTM_SEC_SERVICE_AVCTP, 0); + /* call l2cap connect req */ + p_lcb->ch_state = AVCT_CH_CONN; + if ((p_lcb->ch_lcid = L2CA_ConnectReq(AVCT_PSM, p_lcb->peer_addr)) == 0) { + /* if connect req failed, send ourselves close event */ + avct_lcb_event(p_lcb, AVCT_LCB_LL_CLOSE_EVT, (tAVCT_LCB_EVT *) &result); + } +} + +/******************************************************************************* +** +** Function avct_lcb_unbind_disc +** +** Description Deallocate ccb and call callback with disconnect event. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UNUSED(p_lcb); + + avct_ccb_dealloc(p_data->p_ccb, AVCT_DISCONNECT_CFM_EVT, 0, NULL); +} + +/******************************************************************************* +** +** Function avct_lcb_open_ind +** +** Description Handle an LL_OPEN event. For each allocated ccb already +** bound to this lcb, send a connect event. For each +** unbound ccb with a new PID, bind that ccb to this lcb and +** send a connect event. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + BOOLEAN bind = FALSE; + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + /* if ccb allocated and */ + if (p_ccb->allocated) { + /* if bound to this lcb send connect confirm event */ + if (p_ccb->p_lcb == p_lcb) { + bind = TRUE; + L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_CFM_EVT, + 0, p_lcb->peer_addr); + } + /* if unbound acceptor and lcb doesn't already have a ccb for this PID */ + else if ((p_ccb->p_lcb == NULL) && (p_ccb->cc.role == AVCT_ACP) && + (avct_lcb_has_pid(p_lcb, p_ccb->cc.pid) == NULL)) { + /* bind ccb to lcb and send connect ind event */ + bind = TRUE; + p_ccb->p_lcb = p_lcb; + L2CA_SetTxPriority(p_lcb->ch_lcid, L2CAP_CHNL_PRIORITY_HIGH); + p_ccb->cc.p_ctrl_cback(avct_ccb_to_idx(p_ccb), AVCT_CONNECT_IND_EVT, + 0, p_lcb->peer_addr); + } + } + } + + /* if no ccbs bound to this lcb, disconnect */ + if (bind == FALSE) { + avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data); + } +} + +/******************************************************************************* +** +** Function avct_lcb_open_fail +** +** Description L2CAP channel open attempt failed. Deallocate any ccbs +** on this lcb and send connect confirm event with failure. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { + avct_ccb_dealloc(p_ccb, AVCT_CONNECT_CFM_EVT, + p_data->result, p_lcb->peer_addr); + } + } +} + +/******************************************************************************* +** +** Function avct_lcb_close_ind +** +** Description L2CAP channel closed by peer. Deallocate any initiator +** ccbs on this lcb and send disconnect ind event. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + UNUSED(p_data); + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { + if (p_ccb->cc.role == AVCT_INT) { + avct_ccb_dealloc(p_ccb, AVCT_DISCONNECT_IND_EVT, + 0, p_lcb->peer_addr); + } else { + p_ccb->p_lcb = NULL; + (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), AVCT_DISCONNECT_IND_EVT, + 0, p_lcb->peer_addr); + } + } + } +} + +/******************************************************************************* +** +** Function avct_lcb_close_cfm +** +** Description L2CAP channel closed by us. Deallocate any initiator +** ccbs on this lcb and send disconnect ind or cfm event. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + UINT8 event; + + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { + /* if this ccb initiated close send disconnect cfm otherwise ind */ + if (p_ccb->ch_close) { + p_ccb->ch_close = FALSE; + event = AVCT_DISCONNECT_CFM_EVT; + } else { + event = AVCT_DISCONNECT_IND_EVT; + } + + if (p_ccb->cc.role == AVCT_INT) { + avct_ccb_dealloc(p_ccb, event, p_data->result, p_lcb->peer_addr); + } else { + p_ccb->p_lcb = NULL; + (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, + p_data->result, p_lcb->peer_addr); + } + } + } +} + +/******************************************************************************* +** +** Function avct_lcb_bind_conn +** +** Description Bind ccb to lcb and send connect cfm event. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + p_data->p_ccb->p_lcb = p_lcb; + (*p_data->p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_data->p_ccb), + AVCT_CONNECT_CFM_EVT, 0, p_lcb->peer_addr); +} + +/******************************************************************************* +** +** Function avct_lcb_chk_disc +** +** Description A ccb wants to close; if it is the last ccb on this lcb, +** close channel. Otherwise just deallocate and call +** callback. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + AVCT_TRACE_WARNING("avct_lcb_chk_disc"); +#if (AVCT_BROWSE_INCLUDED == TRUE) + avct_close_bcb(p_lcb, p_data); +#endif + if (avct_lcb_last_ccb(p_lcb, p_data->p_ccb)) { + AVCT_TRACE_WARNING("closing"); + p_data->p_ccb->ch_close = TRUE; + avct_lcb_event(p_lcb, AVCT_LCB_INT_CLOSE_EVT, p_data); + } else { + AVCT_TRACE_WARNING("dealloc ccb"); + avct_lcb_unbind_disc(p_lcb, p_data); + } +} + +/******************************************************************************* +** +** Function avct_lcb_chnl_disc +** +** Description Disconnect L2CAP channel. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UNUSED(p_data); + + L2CA_DisconnectReq(p_lcb->ch_lcid); +} + +/******************************************************************************* +** +** Function avct_lcb_bind_fail +** +** Description Deallocate ccb and call callback with connect event +** with failure result. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UNUSED(p_lcb); + + avct_ccb_dealloc(p_data->p_ccb, AVCT_CONNECT_CFM_EVT, AVCT_RESULT_FAIL, NULL); +} + +/******************************************************************************* +** +** Function avct_lcb_cong_ind +** +** Description Handle congestion indication from L2CAP. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + tAVCT_CCB *p_ccb = &avct_cb.ccb[0]; + int i; + UINT8 event; + BT_HDR *p_buf; + + /* set event */ + event = (p_data->cong) ? AVCT_CONG_IND_EVT : AVCT_UNCONG_IND_EVT; + p_lcb->cong = p_data->cong; + if (p_lcb->cong == FALSE && GKI_getfirst(&p_lcb->tx_q)) { + while ( !p_lcb->cong && (p_buf = (BT_HDR *)GKI_dequeue(&p_lcb->tx_q)) != NULL) { + if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) { + p_lcb->cong = TRUE; + } + } + } + + /* send event to all ccbs on this lcb */ + for (i = 0; i < AVCT_NUM_CONN; i++, p_ccb++) { + if (p_ccb->allocated && (p_ccb->p_lcb == p_lcb)) { + (*p_ccb->cc.p_ctrl_cback)(avct_ccb_to_idx(p_ccb), event, 0, p_lcb->peer_addr); + } + } +} + +/******************************************************************************* +** +** Function avct_lcb_discard_msg +** +** Description Discard a message sent in from the API. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UNUSED(p_lcb); + + AVCT_TRACE_WARNING("Dropping msg"); + + GKI_freebuf(p_data->ul_msg.p_buf); +} + +/******************************************************************************* +** +** Function avct_lcb_send_msg +** +** Description Build and send an AVCTP message. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UINT16 curr_msg_len; + UINT8 pkt_type; + UINT8 hdr_len; + BT_HDR *p_buf; + UINT8 *p; + UINT8 nosp = 0; /* number of subsequent packets */ + UINT16 temp; + UINT16 buf_size = p_lcb->peer_mtu + L2CAP_MIN_OFFSET + BT_HDR_SIZE; + + + /* store msg len */ + curr_msg_len = p_data->ul_msg.p_buf->len; + + /* initialize packet type and other stuff */ + if (curr_msg_len <= (p_lcb->peer_mtu - AVCT_HDR_LEN_SINGLE)) { + pkt_type = AVCT_PKT_TYPE_SINGLE; + } else { + pkt_type = AVCT_PKT_TYPE_START; + temp = (curr_msg_len + AVCT_HDR_LEN_START - p_lcb->peer_mtu); + nosp = temp / (p_lcb->peer_mtu - 1) + 1; + if ( (temp % (p_lcb->peer_mtu - 1)) != 0) { + nosp++; + } + } + + /* while we haven't sent all packets */ + while (curr_msg_len != 0) { + /* set header len */ + hdr_len = avct_lcb_pkt_type_len[pkt_type]; + + /* if remaining msg must be fragmented */ + if (p_data->ul_msg.p_buf->len > (p_lcb->peer_mtu - hdr_len)) { + /* get a new buffer for fragment we are sending */ + if ((p_buf = (BT_HDR *) GKI_getbuf(buf_size)) == NULL) { + /* whoops; free original msg buf and bail */ + AVCT_TRACE_ERROR ("avct_lcb_send_msg cannot alloc buffer!!"); + GKI_freebuf(p_data->ul_msg.p_buf); + break; + } + + /* copy portion of data from current message to new buffer */ + p_buf->offset = L2CAP_MIN_OFFSET + hdr_len; + p_buf->len = p_lcb->peer_mtu - hdr_len; + + memcpy((UINT8 *)(p_buf + 1) + p_buf->offset, + (UINT8 *)(p_data->ul_msg.p_buf + 1) + p_data->ul_msg.p_buf->offset, p_buf->len); + + p_data->ul_msg.p_buf->offset += p_buf->len; + p_data->ul_msg.p_buf->len -= p_buf->len; + } else { + p_buf = p_data->ul_msg.p_buf; + } + + curr_msg_len -= p_buf->len; + + /* set up to build header */ + p_buf->len += hdr_len; + p_buf->offset -= hdr_len; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* build header */ + AVCT_BLD_HDR(p, p_data->ul_msg.label, pkt_type, p_data->ul_msg.cr); + if (pkt_type == AVCT_PKT_TYPE_START) { + UINT8_TO_STREAM(p, nosp); + } + if ((pkt_type == AVCT_PKT_TYPE_START) || (pkt_type == AVCT_PKT_TYPE_SINGLE)) { + UINT16_TO_BE_STREAM(p, p_data->ul_msg.p_ccb->cc.pid); + } + + if (p_lcb->cong == TRUE) { + GKI_enqueue (&p_lcb->tx_q, p_buf); + } + + /* send message to L2CAP */ + else { + if (L2CA_DataWrite(p_lcb->ch_lcid, p_buf) == L2CAP_DW_CONGESTED) { + p_lcb->cong = TRUE; + } + } + + /* update pkt type for next packet */ + if (curr_msg_len > (p_lcb->peer_mtu - AVCT_HDR_LEN_END)) { + pkt_type = AVCT_PKT_TYPE_CONT; + } else { + pkt_type = AVCT_PKT_TYPE_END; + } + } + AVCT_TRACE_DEBUG ("avct_lcb_send_msg tx_q_count:%d", GKI_queue_length(&p_lcb->tx_q)); + return; +} + +/******************************************************************************* +** +** Function avct_lcb_free_msg_ind +** +** Description Discard an incoming AVCTP message. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UNUSED(p_lcb); + + if (p_data) { + GKI_freebuf(p_data->p_buf); + } + return; +} + +/******************************************************************************* +** +** Function avct_lcb_msg_ind +** +** Description Handle an incoming AVCTP message. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data) +{ + UINT8 *p; + UINT8 label, type, cr_ipid; + UINT16 pid; + tAVCT_CCB *p_ccb; + BT_HDR *p_buf; + + /* this p_buf is to be reported through p_msg_cback. The layer_specific + * needs to be set properly to indicate that it is received through + * control channel */ + p_data->p_buf->layer_specific = AVCT_DATA_CTRL; + + /* reassemble message; if no message available (we received a fragment) return */ + if ((p_data->p_buf = avct_lcb_msg_asmbl(p_lcb, p_data->p_buf)) == NULL) { + return; + } + + p = (UINT8 *)(p_data->p_buf + 1) + p_data->p_buf->offset; + + /* parse header byte */ + AVCT_PRS_HDR(p, label, type, cr_ipid); + UNUSED(type); + + /* check for invalid cr_ipid */ + if (cr_ipid == AVCT_CR_IPID_INVALID) { + AVCT_TRACE_WARNING("Invalid cr_ipid %d", cr_ipid); + GKI_freebuf(p_data->p_buf); + return; + } + + /* parse and lookup PID */ + BE_STREAM_TO_UINT16(pid, p); + if ((p_ccb = avct_lcb_has_pid(p_lcb, pid)) != NULL) { + /* PID found; send msg up, adjust bt hdr and call msg callback */ + p_data->p_buf->offset += AVCT_HDR_LEN_SINGLE; + p_data->p_buf->len -= AVCT_HDR_LEN_SINGLE; + (*p_ccb->cc.p_msg_cback)(avct_ccb_to_idx(p_ccb), label, cr_ipid, p_data->p_buf); + } else { + /* PID not found; drop message */ + AVCT_TRACE_WARNING("No ccb for PID=%x", pid); + GKI_freebuf(p_data->p_buf); + + /* if command send reject */ + if (cr_ipid == AVCT_CMD) { + if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVCT_CMD_POOL_ID)) != NULL) { + p_buf->len = AVCT_HDR_LEN_SINGLE; + p_buf->offset = AVCT_MSG_OFFSET - AVCT_HDR_LEN_SINGLE; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + AVCT_BLD_HDR(p, label, AVCT_PKT_TYPE_SINGLE, AVCT_REJ); + UINT16_TO_BE_STREAM(p, pid); + L2CA_DataWrite(p_lcb->ch_lcid, p_buf); + } + } + } +} + +#endif /* #if (defined(AVCT_INCLUDED) && AVCT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avct/include/avct_defs.h b/components/bt/bluedroid/stack/avct/include/avct_defs.h new file mode 100644 index 0000000000..30b8859fe0 --- /dev/null +++ b/components/bt/bluedroid/stack/avct/include/avct_defs.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This contains constants definitions and other information from the AVCTP + * specification. This file is intended for use internal to AVCT only. + * + ******************************************************************************/ +#ifndef AVCT_DEFS_H +#define AVCT_DEFS_H + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* packet type */ +#define AVCT_PKT_TYPE_SINGLE 0 /* single packet */ +#define AVCT_PKT_TYPE_START 1 /* start packet */ +#define AVCT_PKT_TYPE_CONT 2 /* continue packet */ +#define AVCT_PKT_TYPE_END 3 /* end packet */ + +/* header lengths for different packet types */ +#define AVCT_HDR_LEN_SINGLE 3 +#define AVCT_HDR_LEN_START 4 +#define AVCT_HDR_LEN_CONT 1 +#define AVCT_HDR_LEN_END 1 + +/* invalid cr+ipid value */ +#define AVCT_CR_IPID_INVALID 1 + +/***************************************************************************** +** message parsing and building macros +*****************************************************************************/ + +#define AVCT_BLD_HDR(p, label, type, cr_ipid) \ + *(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid); + +#define AVCT_PRS_HDR(p, label, type, cr_ipid) \ + label = *(p) >> 4; \ + type = (*(p) >> 2) & 3; \ + cr_ipid = *(p)++ & 3; + +#define AVCT_PRS_PKT_TYPE(p, type) \ + type = (*(p) >> 2) & 3; + +#endif /* AVCT_DEFS_H */ diff --git a/components/bt/bluedroid/stack/avct/include/avct_int.h b/components/bt/bluedroid/stack/avct/include/avct_int.h new file mode 100644 index 0000000000..c922fe1166 --- /dev/null +++ b/components/bt/bluedroid/stack/avct/include/avct_int.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * + * Copyright (C) 2003-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains interfaces which are internal to AVCTP. + * + ******************************************************************************/ +#ifndef AVCT_INT_H +#define AVCT_INT_H + +#include "gki.h" +#include "avct_api.h" +#include "avct_defs.h" +#include "l2c_api.h" + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* lcb state machine events */ +enum { + AVCT_LCB_UL_BIND_EVT, + AVCT_LCB_UL_UNBIND_EVT, + AVCT_LCB_UL_MSG_EVT, + AVCT_LCB_INT_CLOSE_EVT, + AVCT_LCB_LL_OPEN_EVT, + AVCT_LCB_LL_CLOSE_EVT, + AVCT_LCB_LL_MSG_EVT, + AVCT_LCB_LL_CONG_EVT +}; + + +/* "states" used for L2CAP channel */ +#define AVCT_CH_IDLE 0 /* No connection */ +#define AVCT_CH_CONN 1 /* Waiting for connection confirm */ +#define AVCT_CH_CFG 2 /* Waiting for configuration complete */ +#define AVCT_CH_OPEN 3 /* Channel opened */ + +/* "no event" indicator used by ccb dealloc */ +#define AVCT_NO_EVT 0xFF + +/***************************************************************************** +** data types +*****************************************************************************/ +/* sub control block type - common data members for tAVCT_LCB and tAVCT_BCB */ +typedef struct { + UINT16 peer_mtu; /* peer l2c mtu */ + UINT16 ch_result; /* L2CAP connection result value */ + UINT16 ch_lcid; /* L2CAP channel LCID */ + UINT8 allocated; /* 0, not allocated. index+1, otherwise. */ + UINT8 state; /* The state machine state */ + UINT8 ch_state; /* L2CAP channel state */ + UINT8 ch_flags; /* L2CAP configuration flags */ +} tAVCT_SCB; + +/* link control block type */ +typedef struct { + UINT16 peer_mtu; /* peer l2c mtu */ + UINT16 ch_result; /* L2CAP connection result value */ + UINT16 ch_lcid; /* L2CAP channel LCID */ + UINT8 allocated; /* 0, not allocated. index+1, otherwise. */ + UINT8 state; /* The state machine state */ + UINT8 ch_state; /* L2CAP channel state */ + UINT8 ch_flags; /* L2CAP configuration flags */ + BT_HDR *p_rx_msg; /* Message being reassembled */ + UINT16 conflict_lcid; /* L2CAP channel LCID */ + BD_ADDR peer_addr; /* BD address of peer */ + BUFFER_Q tx_q; /* Transmit data buffer queue */ + BOOLEAN cong; /* TRUE, if congested */ +} tAVCT_LCB; + +/* browse control block type */ +typedef struct { + UINT16 peer_mtu; /* peer l2c mtu */ + UINT16 ch_result; /* L2CAP connection result value */ + UINT16 ch_lcid; /* L2CAP channel LCID */ + UINT8 allocated; /* 0, not allocated. index+1, otherwise. */ + UINT8 state; /* The state machine state */ + UINT8 ch_state; /* L2CAP channel state */ + UINT8 ch_flags; /* L2CAP configuration flags */ + BT_HDR *p_tx_msg; /* Message to be sent - in case the browsing channel is not open when MsgReg is called */ + UINT8 ch_close; /* CCB index+1, if CCB initiated channel close */ +} tAVCT_BCB; + +#define AVCT_ALOC_LCB 0x01 +#define AVCT_ALOC_BCB 0x02 +/* connection control block */ +typedef struct { + tAVCT_CC cc; /* parameters from connection creation */ + tAVCT_LCB *p_lcb; /* Associated LCB */ + tAVCT_BCB *p_bcb; /* associated BCB */ + BOOLEAN ch_close; /* Whether CCB initiated channel close */ + UINT8 allocated; /* Whether LCB/BCB is allocated */ +} tAVCT_CCB; + +/* data type associated with UL_MSG_EVT */ +typedef struct { + BT_HDR *p_buf; + tAVCT_CCB *p_ccb; + UINT8 label; + UINT8 cr; +} tAVCT_UL_MSG; + +/* union associated with lcb state machine events */ +typedef union { + tAVCT_UL_MSG ul_msg; + BT_HDR *p_buf; + tAVCT_CCB *p_ccb; + UINT16 result; + BOOLEAN cong; + UINT8 err_code; +} tAVCT_LCB_EVT; + +/* Control block for AVCT */ +typedef struct { + tAVCT_LCB lcb[AVCT_NUM_LINKS]; /* link control blocks */ + tAVCT_BCB bcb[AVCT_NUM_LINKS]; /* browse control blocks */ + tAVCT_CCB ccb[AVCT_NUM_CONN]; /* connection control blocks */ + UINT16 mtu; /* our L2CAP MTU */ + UINT16 mtu_br; /* our L2CAP MTU for the Browsing channel */ + UINT8 trace_level; /* trace level */ +} tAVCT_CB; + +/***************************************************************************** +** function declarations +*****************************************************************************/ + +/* LCB function declarations */ +extern void avct_lcb_event(tAVCT_LCB *p_lcb, UINT8 event, tAVCT_LCB_EVT *p_data); +#if (AVCT_BROWSE_INCLUDED == TRUE) +extern void avct_bcb_event(tAVCT_BCB *p_bcb, UINT8 event, tAVCT_LCB_EVT *p_data); +extern void avct_close_bcb(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern tAVCT_LCB *avct_lcb_by_bcb(tAVCT_BCB *p_bcb); +extern tAVCT_BCB *avct_bcb_by_lcb(tAVCT_LCB *p_lcb); +extern BOOLEAN avct_bcb_last_ccb(tAVCT_BCB *p_bcb, tAVCT_CCB *p_ccb_last); +extern tAVCT_BCB *avct_bcb_by_lcid(UINT16 lcid); +#endif +extern tAVCT_LCB *avct_lcb_by_bd(BD_ADDR bd_addr); +extern tAVCT_LCB *avct_lcb_alloc(BD_ADDR bd_addr); +extern void avct_lcb_dealloc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern tAVCT_LCB *avct_lcb_by_lcid(UINT16 lcid); +extern tAVCT_CCB *avct_lcb_has_pid(tAVCT_LCB *p_lcb, UINT16 pid); +extern BOOLEAN avct_lcb_last_ccb(tAVCT_LCB *p_lcb, tAVCT_CCB *p_ccb_last); + +/* LCB action functions */ +extern void avct_lcb_chnl_open(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_unbind_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_open_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_open_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_close_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_close_cfm(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_bind_conn(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_chk_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_chnl_disc(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_bind_fail(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_cong_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_discard_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_send_msg(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); +extern void avct_lcb_free_msg_ind(tAVCT_LCB *p_lcb, tAVCT_LCB_EVT *p_data); + +/* BCB action functions */ +#if (AVCT_BROWSE_INCLUDED == TRUE) +typedef void (*tAVCT_BCB_ACTION)(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_chnl_open(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_unbind_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_open_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_open_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_close_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_close_cfm(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_bind_conn(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_chk_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_chnl_disc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_bind_fail(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_cong_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_discard_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_send_msg(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); +extern void avct_bcb_free_msg_ind(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); + +extern void avct_bcb_dealloc(tAVCT_BCB *p_bcb, tAVCT_LCB_EVT *p_data); + +extern const tAVCT_BCB_ACTION avct_bcb_action[]; +extern const UINT8 avct_lcb_pkt_type_len[]; +extern const tL2CAP_FCR_OPTS avct_l2c_br_fcr_opts_def; +#endif + +/* CCB function declarations */ +extern tAVCT_CCB *avct_ccb_alloc(tAVCT_CC *p_cc); +extern void avct_ccb_dealloc(tAVCT_CCB *p_ccb, UINT8 event, UINT16 result, BD_ADDR bd_addr); +extern UINT8 avct_ccb_to_idx(tAVCT_CCB *p_ccb); +extern tAVCT_CCB *avct_ccb_by_idx(UINT8 idx); + + +/***************************************************************************** +** global data +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Main control block */ +#if AVCT_DYNAMIC_MEMORY == FALSE +extern tAVCT_CB avct_cb; +#else +extern tAVCT_CB *avct_cb_ptr; +#define avct_cb (*avct_cb_ptr) +#endif + +/* L2CAP callback registration structure */ +extern const tL2CAP_APPL_INFO avct_l2c_appl; +#if (AVCT_BROWSE_INCLUDED == TRUE) +extern const tL2CAP_APPL_INFO avct_l2c_br_appl; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* AVCT_INT_H */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_ad.c b/components/bt/bluedroid/stack/avdt/avdt_ad.c new file mode 100644 index 0000000000..4b37bf3298 --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_ad.c @@ -0,0 +1,595 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains the AVDTP adaption layer. + * + ******************************************************************************/ + +// #include +#include "bt_trace.h" +#include + +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "l2c_api.h" +#include "l2cdefs.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) +/******************************************************************************* +** +** Function avdt_ad_type_to_tcid +** +** Description Derives the TCID from the channel type and SCB. +** +** +** Returns TCID value. +** +*******************************************************************************/ +UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb) +{ + UINT8 scb_idx; + + if (type == AVDT_CHAN_SIG) { + return 0; + } else { + scb_idx = avdt_scb_to_hdl(p_scb) - 1; + /* + AVDT_TRACE_DEBUG("type: %d, tcid: %d", type, ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type)); + */ + return ((scb_idx * (AVDT_CHAN_NUM_TYPES - 1)) + type); + } +} + +/******************************************************************************* +** +** Function avdt_ad_tcid_to_type +** +** Description Derives the channel type from the TCID. +** +** +** Returns Channel type value. +** +*******************************************************************************/ +static UINT8 avdt_ad_tcid_to_type(UINT8 tcid) +{ + UINT8 type; + + if (tcid == 0) { + type = AVDT_CHAN_SIG; + } else { + /* tcid translates to type based on number of channels, as follows: + ** only media channel : tcid=1,2,3,4,5,6... type=1,1,1,1,1,1... + ** media and report : tcid=1,2,3,4,5,6... type=1,2,1,2,1,2... + ** media, report, recov : tcid=1,2,3,4,5,6... type=1,2,3,1,2,3... + */ + type = ((tcid + AVDT_CHAN_NUM_TYPES - 2) % (AVDT_CHAN_NUM_TYPES - 1)) + 1; + } + AVDT_TRACE_DEBUG("tcid: %d, type: %d\n", tcid, type); + return type; +} + + +/******************************************************************************* +** +** Function avdt_ad_init +** +** Description Initialize adaption layer. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ad_init(void) +{ + int i; + tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl; + memset(&avdt_cb.ad, 0, sizeof(tAVDT_AD)); + + /* make sure the peer_mtu is a valid value */ + for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { + p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; + } +} + + +/******************************************************************************* +** +** Function avdt_ad_tc_tbl_by_st +** +** Description Find adaption layer transport channel table entry matching +** the given state. +** +** +** Returns Pointer to matching entry. For control channel it returns +** the matching entry. For media or other it returns the +** first matching entry (there could be more than one). +** +*******************************************************************************/ +tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state) +{ + int i; + tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl; + UINT8 ccb_idx; + + if (p_ccb == NULL) { + /* resending security req */ + for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { + /* must be AVDT_CHAN_SIG - tcid always zero */ + if ((p_tbl->tcid == 0) && + (p_tbl->state == state)) { + break; + } + } + } else { + ccb_idx = avdt_ccb_to_idx(p_ccb); + + for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { + if (type == AVDT_CHAN_SIG) { + /* if control channel, tcid always zero */ + if ((p_tbl->tcid == 0) && + (p_tbl->ccb_idx == ccb_idx) && + (p_tbl->state == state)) { + break; + } + } else { + /* if other channel, tcid is always > zero */ + if ((p_tbl->tcid > 0) && + (p_tbl->ccb_idx == ccb_idx) && + (p_tbl->state == state)) { + break; + } + } + } + } + + /* if nothing found return null */ + if (i == AVDT_NUM_TC_TBL) { + p_tbl = NULL; + } + + return p_tbl; +} + + +/******************************************************************************* +** +** Function avdt_ad_tc_tbl_by_lcid +** +** Description Find adaption layer transport channel table entry by LCID. +** +** +** Returns Pointer to entry. +** +*******************************************************************************/ +tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid) +{ + UINT8 idx; + + idx = avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID]; + + if (idx < AVDT_NUM_TC_TBL) { + return &avdt_cb.ad.tc_tbl[idx]; + } else { + return NULL; + } +} + + +/******************************************************************************* +** +** Function avdt_ad_tc_tbl_by_type +** +** Description This function retrieves the transport channel table entry +** for a particular channel. +** +** +** Returns Pointer to transport channel table entry. +** +*******************************************************************************/ +tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb) +{ + UINT8 tcid; + int i; + tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl; + UINT8 ccb_idx = avdt_ccb_to_idx(p_ccb); + + /* get tcid from type, scb */ + tcid = avdt_ad_type_to_tcid(type, p_scb); + + for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { + if ((p_tbl->tcid == tcid) && (p_tbl->ccb_idx == ccb_idx)) { + break; + } + } + + assert(i != AVDT_NUM_TC_TBL); + + return p_tbl; +} + + +/******************************************************************************* +** +** Function avdt_ad_tc_tbl_alloc +** +** Description Allocate an entry in the traffic channel table. +** +** +** Returns Pointer to entry. +** +*******************************************************************************/ +tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb) +{ + int i; + tAVDT_TC_TBL *p_tbl = avdt_cb.ad.tc_tbl; + + /* find next free entry in tc table */ + for (i = 0; i < AVDT_NUM_TC_TBL; i++, p_tbl++) { + if (p_tbl->state == AVDT_AD_ST_UNUSED) { + break; + } + } + + /* sanity check */ + assert(i != AVDT_NUM_TC_TBL); + + + /* initialize entry */ + p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; + p_tbl->cfg_flags = 0; + p_tbl->ccb_idx = avdt_ccb_to_idx(p_ccb); + p_tbl->state = AVDT_AD_ST_IDLE; + return p_tbl; + +} + +/******************************************************************************* +** +** Function avdt_ad_tc_tbl_to_idx +** +** Description Convert a transport channel table entry to an index. +** +** +** Returns Index value. +** +*******************************************************************************/ +UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl) +{ + AVDT_TRACE_DEBUG("avdt_ad_tc_tbl_to_idx: %d\n", (p_tbl - avdt_cb.ad.tc_tbl)); + /* use array arithmetic to determine index */ + return (UINT8) (p_tbl - avdt_cb.ad.tc_tbl); +} + +/******************************************************************************* +** +** Function avdt_ad_tc_close_ind +** +** Description This function is called by the L2CAP interface when the +** L2CAP channel is closed. It looks up the CCB or SCB for +** the channel and sends it a close event. The reason +** parameter is the same value passed by the L2CAP +** callback function. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason) +{ + tAVDT_CCB *p_ccb; + tAVDT_SCB *p_scb; + tAVDT_SCB_TC_CLOSE close; + // UNUSED(reason); + + close.old_tc_state = p_tbl->state; + + /* clear avdt_ad_tc_tbl entry */ + p_tbl->state = AVDT_AD_ST_UNUSED; + p_tbl->cfg_flags = 0; + p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; + + AVDT_TRACE_DEBUG("avdt_ad_tc_close_ind tcid: %d, old: %d\n", + p_tbl->tcid, close.old_tc_state); + + /* if signaling channel, notify ccb that channel open */ + if (p_tbl->tcid == 0) { + p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); + p_ccb->disc_rsn = (reason == AVDT_DISC_RSN_ABNORMAL) ? AVDT_DISC_RSN_ABNORMAL : AVDT_DISC_RSN_NORMAL; + avdt_ccb_event(p_ccb, AVDT_CCB_LL_CLOSE_EVT, NULL); + } + /* if media or other channel, notify scb that channel close */ + else { + /* look up scb in stream routing table by ccb, tcid */ + p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); + if (p_scb != NULL) { + close.tcid = p_tbl->tcid; + close.type = avdt_ad_tcid_to_type(p_tbl->tcid); + close.disc_rsn = (reason == AVDT_DISC_RSN_ABNORMAL) ? AVDT_DISC_RSN_ABNORMAL : AVDT_DISC_RSN_NORMAL; + avdt_scb_event(p_scb, AVDT_SCB_TC_CLOSE_EVT, (tAVDT_SCB_EVT *)&close); + } + } +} + +/******************************************************************************* +** +** Function avdt_ad_tc_open_ind +** +** Description This function is called by the L2CAP interface when +** the L2CAP channel is opened. It looks up the CCB or SCB +** for the channel and sends it an open event. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl) +{ + tAVDT_CCB *p_ccb; + tAVDT_SCB *p_scb; + tAVDT_OPEN open; + tAVDT_EVT_HDR evt; + + p_tbl->state = AVDT_AD_ST_OPEN; + + /* if signaling channel, notify ccb that channel open */ + if (p_tbl->tcid == 0) { + /* set the signal channel to use high priority within the ACL link */ + L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, L2CAP_CHNL_PRIORITY_HIGH); + + p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); + /* use err_param to indicate the role of connection. + * AVDT_ACP, if ACP */ + evt.err_param = AVDT_INT; + if (p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP) { + evt.err_param = AVDT_ACP; + } + avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT *)&evt); + } + /* if media or other channel, notify scb that channel open */ + else { + /* look up scb in stream routing table by ccb, tcid */ + p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); + + /* put lcid in event data */ + if (p_scb != NULL) { + open.peer_mtu = p_tbl->peer_mtu; + open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid; + open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid); + avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT *) &open); + } + } +} + + +/******************************************************************************* +** +** Function avdt_ad_tc_cong_ind +** +** Description This function is called by the L2CAP interface layer when +** L2CAP calls the congestion callback. It looks up the CCB +** or SCB for the channel and sends it a congestion event. +** The is_congested parameter is the same value passed by +** the L2CAP callback function. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested) +{ + tAVDT_CCB *p_ccb; + tAVDT_SCB *p_scb; + + /* if signaling channel, notify ccb of congestion */ + if (p_tbl->tcid == 0) { + p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); + avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT *) &is_congested); + } + /* if media or other channel, notify scb that channel open */ + else { + /* look up scb in stream routing table by ccb, tcid */ + p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); + if (p_scb != NULL) { + avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, (tAVDT_SCB_EVT *) &is_congested); + } + } +} + + +/******************************************************************************* +** +** Function avdt_ad_tc_data_ind +** +** Description This function is called by the L2CAP interface layer when +** incoming data is received from L2CAP. It looks up the CCB +** or SCB for the channel and routes the data accordingly. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf) +{ + tAVDT_CCB *p_ccb; + tAVDT_SCB *p_scb; + + /* store type (media, recovery, reporting) */ + p_buf->layer_specific = avdt_ad_tcid_to_type(p_tbl->tcid); + + + /* if signaling channel, handle control message */ + if (p_tbl->tcid == 0) { + p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); + avdt_msg_ind(p_ccb, p_buf); + } + /* if media or other channel, send event to scb */ + else { + p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); + if (p_scb != NULL) { + avdt_scb_event(p_scb, AVDT_SCB_TC_DATA_EVT, (tAVDT_SCB_EVT *) &p_buf); + } else { + GKI_freebuf(p_buf); + AVDT_TRACE_ERROR(" avdt_ad_tc_data_ind buffer freed"); + } + } +} + +/******************************************************************************* +** +** Function avdt_ad_write_req +** +** Description This function is called by a CCB or SCB to send data to a +** transport channel. It looks up the LCID of the channel +** based on the type, CCB, and SCB (if present). Then it +** passes the data to L2CA_DataWrite(). +** +** +** Returns AVDT_AD_SUCCESS, if data accepted, else FALSE +** AVDT_AD_CONGESTED, if data accepted and the channel is congested +** AVDT_AD_FAILED, if error +** +*******************************************************************************/ +UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf) +{ + UINT8 tcid; + + /* get tcid from type, scb */ + tcid = avdt_ad_type_to_tcid(type, p_scb); + + + return L2CA_DataWrite(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid, p_buf); +} + + +/******************************************************************************* +** +** Function avdt_ad_open_req +** +** Description This function is called by a CCB or SCB to open a transport +** channel. This function allocates and initializes a +** transport channel table entry. The channel can be opened +** in two roles: as an initiator or acceptor. When opened +** as an initiator the function will start an L2CAP connection. +** When opened as an acceptor the function simply configures +** the table entry to listen for an incoming channel. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role) +{ + tAVDT_TC_TBL *p_tbl; + UINT16 lcid; + + if ((p_tbl = avdt_ad_tc_tbl_alloc(p_ccb)) == NULL) { + AVDT_TRACE_ERROR("avdt_ad_open_req: Cannot allocate p_tbl"); + return; + } + + + p_tbl->tcid = avdt_ad_type_to_tcid(type, p_scb); + AVDT_TRACE_DEBUG("avdt_ad_open_req: type: %d, role: %d, tcid:%d\n", + type, role, p_tbl->tcid); + + if (type == AVDT_CHAN_SIG) { + /* if signaling, get mtu from registration control block */ + p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu; + p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO; + } else { + /* otherwise get mtu from scb */ + p_tbl->my_mtu = p_scb->cs.mtu; + p_tbl->my_flush_to = p_scb->cs.flush_to; + + /* also set scb_hdl in rt_tbl */ + avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].scb_hdl = avdt_scb_to_hdl(p_scb); + AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].scb_hdl = %d\n", + avdt_ccb_to_idx(p_ccb), p_tbl->tcid, + avdt_scb_to_hdl(p_scb)); + } + + /* if we're acceptor, we're done; just sit back and listen */ + if (role == AVDT_ACP) { + p_tbl->state = AVDT_AD_ST_ACP; + } + /* else we're inititator, start the L2CAP connection */ + else { + p_tbl->state = AVDT_AD_ST_CONN; + + /* call l2cap connect req */ + if ((lcid = L2CA_ConnectReq(AVDT_PSM, p_ccb->peer_addr)) != 0) { + /* if connect req ok, store tcid in lcid table */ + avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl); + AVDT_TRACE_DEBUG("avdt_cb.ad.lcid_tbl[%d] = %d\n", + (lcid - L2CAP_BASE_APPL_CID), avdt_ad_tc_tbl_to_idx(p_tbl)); + + avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid; + AVDT_TRACE_DEBUG("avdt_cb.ad.rt_tbl[%d][%d].lcid = 0x%x\n", + avdt_ccb_to_idx(p_ccb), p_tbl->tcid, + lcid); + } else { + /* if connect req failed, call avdt_ad_tc_close_ind() */ + avdt_ad_tc_close_ind(p_tbl, 0); + } + } +} + +/******************************************************************************* +** +** Function avdt_ad_close_req +** +** Description This function is called by a CCB or SCB to close a +** transport channel. The function looks up the LCID for the +** channel and calls L2CA_DisconnectReq(). +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb) +{ + UINT8 tcid; + tAVDT_TC_TBL *p_tbl; + + p_tbl = avdt_ad_tc_tbl_by_type(type, p_ccb, p_scb); + AVDT_TRACE_DEBUG("avdt_ad_close_req state: %d\n", p_tbl->state); + + switch (p_tbl->state) { + case AVDT_AD_ST_UNUSED: + /* probably for reporting */ + break; + case AVDT_AD_ST_ACP: + /* if we're listening on this channel, send ourselves a close ind */ + avdt_ad_tc_close_ind(p_tbl, 0); + break; + default: + /* get tcid from type, scb */ + tcid = avdt_ad_type_to_tcid(type, p_scb); + + /* call l2cap disconnect req */ + L2CA_DisconnectReq(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid); + } +} + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_api.c b/components/bt/bluedroid/stack/avdt/avdt_api.c new file mode 100644 index 0000000000..1fd534f6ed --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_api.c @@ -0,0 +1,1345 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains API of the audio/video distribution transport + * protocol. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "l2c_api.h" +#include "btm_api.h" +#include "btu.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) + +/* Control block for AVDT */ +#if AVDT_DYNAMIC_MEMORY == FALSE +tAVDT_CB avdt_cb; +#endif + +/******************************************************************************* +** +** Function avdt_process_timeout +** +** Description This function is called by BTU when an AVDTP timer +** expires. The function sends a timer event to the +** appropriate CCB or SCB state machine. +** +** This function is for use internal to the stack only. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_process_timeout(TIMER_LIST_ENT *p_tle) +{ + UINT8 event = 0; + UINT8 err_code = AVDT_ERR_TIMEOUT; + + switch (p_tle->event) { + case BTU_TTYPE_AVDT_CCB_RET: + event = AVDT_CCB_RET_TOUT_EVT + AVDT_CCB_MKR; + break; + + case BTU_TTYPE_AVDT_CCB_RSP: + event = AVDT_CCB_RSP_TOUT_EVT + AVDT_CCB_MKR; + break; + + case BTU_TTYPE_AVDT_CCB_IDLE: + event = AVDT_CCB_IDLE_TOUT_EVT + AVDT_CCB_MKR; + break; + + case BTU_TTYPE_AVDT_SCB_TC: + event = AVDT_SCB_TC_TOUT_EVT; + break; + + default: + break; + } + + if (event & AVDT_CCB_MKR) { + avdt_ccb_event((tAVDT_CCB *) p_tle->param, (UINT8) (event & ~AVDT_CCB_MKR), + (tAVDT_CCB_EVT *) &err_code); + } else { + avdt_scb_event((tAVDT_SCB *) p_tle->param, event, NULL); + } +} + +/******************************************************************************* +** +** Function AVDT_Register +** +** Description This is the system level registration function for the +** AVDTP protocol. This function initializes AVDTP and +** prepares the protocol stack for its use. This function +** must be called once by the system or platform using AVDTP +** before the other functions of the API an be used. +** +** +** Returns void +** +*******************************************************************************/ +void AVDT_Register(tAVDT_REG *p_reg, tAVDT_CTRL_CBACK *p_cback) +{ + /* register PSM with L2CAP */ + L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO *) &avdt_l2c_appl); + + /* set security level */ + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask, + AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG); + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask, + AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG); + + /* do not use security on the media channel */ + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, + AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA); + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, + AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_MEDIA); + +#if AVDT_REPORTING == TRUE + /* do not use security on the reporting channel */ + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, + AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT); + BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_AVDTP_NOSEC, BTM_SEC_NONE, + AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_REPORT); +#endif + + /* initialize AVDTP data structures */ + avdt_scb_init(); + avdt_ccb_init(); + avdt_ad_init(); + + /* copy registration struct */ + memcpy(&avdt_cb.rcb, p_reg, sizeof(tAVDT_REG)); + avdt_cb.p_conn_cback = p_cback; +} + +/******************************************************************************* +** +** Function AVDT_Deregister +** +** Description This function is called to deregister use AVDTP protocol. +** It is called when AVDTP is no longer being used by any +** application in the system. Before this function can be +** called, all streams must be removed with AVDT_RemoveStream(). +** +** +** Returns void +** +*******************************************************************************/ +void AVDT_Deregister(void) +{ + /* deregister PSM with L2CAP */ + L2CA_Deregister(AVDT_PSM); +} + +/******************************************************************************* +** +** Function AVDT_SINK_Activate +** +** Description Activate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made false in case of activation. A2DP SRC +** will receive in_use as false and can open A2DP Sink +** connection +** +** Returns void. +** +*******************************************************************************/ +void AVDT_SINK_Activate() +{ + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + int i; + AVDT_TRACE_DEBUG("AVDT_SINK_Activate"); + /* for all allocated scbs */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { + if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) { + AVDT_TRACE_DEBUG("AVDT_SINK_Activate found scb"); + p_scb->sink_activated = TRUE; + /* update in_use */ + p_scb->in_use = FALSE; + break; + } + } +} + +/******************************************************************************* +** +** Function AVDT_SINK_Deactivate +** +** Description Deactivate SEP of A2DP Sink. In Use parameter is adjusted. +** In Use will be made TRUE in case of activation. A2DP SRC +** will receive in_use as true and will not open A2DP Sink +** connection +** +** Returns void. +** +*******************************************************************************/ +void AVDT_SINK_Deactivate() +{ + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + int i; + AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate"); + /* for all allocated scbs */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { + if ((p_scb->allocated) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) { + AVDT_TRACE_DEBUG("AVDT_SINK_Deactivate, found scb"); + p_scb->sink_activated = FALSE; + /* update in_use */ + p_scb->in_use = TRUE; + break; + } + } +} + +void AVDT_AbortReq(UINT8 handle) +{ + AVDT_TRACE_ERROR("%s\n", __func__); + + tAVDT_SCB *p_scb = avdt_scb_by_hdl(handle); + if (p_scb != NULL) { + avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_REQ_EVT, NULL); + } else { + AVDT_TRACE_ERROR("%s Improper SCB, can not abort the stream\n", __func__); + } +} + +/******************************************************************************* +** +** Function AVDT_CreateStream +** +** Description Create a stream endpoint. After a stream endpoint is +** created an application can initiate a connection between +** this endpoint and an endpoint on a peer device. In +** addition, a peer device can discover, get the capabilities, +** and connect to this endpoint. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_CreateStream(UINT8 *p_handle, tAVDT_CS *p_cs) +{ + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB *p_scb; + + /* Verify parameters; if invalid, return failure */ + if (((p_cs->cfg.psc_mask & (~AVDT_PSC)) != 0) || (p_cs->p_ctrl_cback == NULL)) { + result = AVDT_BAD_PARAMS; + } + /* Allocate scb; if no scbs, return failure */ + else if ((p_scb = avdt_scb_alloc(p_cs)) == NULL) { + result = AVDT_NO_RESOURCES; + } else { + *p_handle = avdt_scb_to_hdl(p_scb); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_RemoveStream +** +** Description Remove a stream endpoint. This function is called when +** the application is no longer using a stream endpoint. +** If this function is called when the endpoint is connected +** the connection is closed and then the stream endpoint +** is removed. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_RemoveStream(UINT8 handle) +{ + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB *p_scb; + + /* look up scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } else { + /* send remove event to scb */ + avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_DiscoverReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and discovers +** the stream endpoints on the peer device. (Please note +** that AVDTP discovery is unrelated to SDP discovery). +** This function can be called at any time regardless of whether +** there is an AVDTP connection to the peer device. +** +** When discovery is complete, an AVDT_DISCOVER_CFM_EVT +** is sent to the application via its callback function. +** The application must not call AVDT_GetCapReq() or +** AVDT_DiscoverReq() again to the same device until +** discovery is complete. +** +** The memory addressed by sep_info is allocated by the +** application. This memory is written to by AVDTP as part +** of the discovery procedure. This memory must remain +** accessible until the application receives the +** AVDT_DISCOVER_CFM_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_DiscoverReq(BD_ADDR bd_addr, tAVDT_SEP_INFO *p_sep_info, + UINT8 max_seps, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB *p_ccb; + UINT16 result = AVDT_SUCCESS; + tAVDT_CCB_EVT evt; + + /* find channel control block for this bd addr; if none, allocate one */ + if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) { + if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL) { + /* could not allocate channel control block */ + result = AVDT_NO_RESOURCES; + } + } + + if (result == AVDT_SUCCESS) { + /* make sure no discovery or get capabilities req already in progress */ + if (p_ccb->proc_busy) { + result = AVDT_BUSY; + } + /* send event to ccb */ + else { + evt.discover.p_sep_info = p_sep_info; + evt.discover.num_seps = max_seps; + evt.discover.p_cback = p_cback; + avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_REQ_EVT, &evt); + } + } + return result; +} + +/******************************************************************************* +** +** Function avdt_get_cap_req +** +** Description internal function to serve both AVDT_GetCapReq and +** AVDT_GetAllCapReq +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +static UINT16 avdt_get_cap_req(BD_ADDR bd_addr, tAVDT_CCB_API_GETCAP *p_evt) +{ + tAVDT_CCB *p_ccb = NULL; + UINT16 result = AVDT_SUCCESS; + + /* verify SEID */ + if ((p_evt->single.seid < AVDT_SEID_MIN) || (p_evt->single.seid > AVDT_SEID_MAX)) { + AVDT_TRACE_ERROR("seid: %d\n", p_evt->single.seid); + result = AVDT_BAD_PARAMS; + } + /* find channel control block for this bd addr; if none, allocate one */ + else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) { + if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL) { + /* could not allocate channel control block */ + result = AVDT_NO_RESOURCES; + } + } + + if (result == AVDT_SUCCESS) { + /* make sure no discovery or get capabilities req already in progress */ + if (p_ccb->proc_busy) { + result = AVDT_BUSY; + } + /* send event to ccb */ + else { + avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_REQ_EVT, (tAVDT_CCB_EVT *)p_evt); + } + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_GetCapReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and gets the +** capabilities of a stream endpoint on the peer device. +** This function can be called at any time regardless of +** whether there is an AVDTP connection to the peer device. +** +** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is +** sent to the application via its callback function. The +** application must not call AVDT_GetCapReq() or +** AVDT_DiscoverReq() again until the procedure is complete. +** +** The memory pointed to by p_cfg is allocated by the +** application. This memory is written to by AVDTP as part +** of the get capabilities procedure. This memory must +** remain accessible until the application receives +** the AVDT_GETCAP_CFM_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_GetCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB_API_GETCAP getcap; + + getcap.single.seid = seid; + getcap.single.sig_id = AVDT_SIG_GETCAP; + getcap.p_cfg = p_cfg; + getcap.p_cback = p_cback; + return avdt_get_cap_req (bd_addr, &getcap); +} + +/******************************************************************************* +** +** Function AVDT_GetAllCapReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and gets the +** capabilities of a stream endpoint on the peer device. +** This function can be called at any time regardless of +** whether there is an AVDTP connection to the peer device. +** +** When the procedure is complete, an AVDT_GETCAP_CFM_EVT is +** sent to the application via its callback function. The +** application must not call AVDT_GetCapReq() or +** AVDT_DiscoverReq() again until the procedure is complete. +** +** The memory pointed to by p_cfg is allocated by the +** application. This memory is written to by AVDTP as part +** of the get capabilities procedure. This memory must +** remain accessible until the application receives +** the AVDT_GETCAP_CFM_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_GetAllCapReq(BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB_API_GETCAP getcap; + + getcap.single.seid = seid; + getcap.single.sig_id = AVDT_SIG_GET_ALLCAP; + getcap.p_cfg = p_cfg; + getcap.p_cback = p_cback; + return avdt_get_cap_req (bd_addr, &getcap); +} + +/******************************************************************************* +** +** Function AVDT_DelayReport +** +** Description This functions sends a Delay Report to the peer device +** that is associated with a particular SEID. +** This function is called by SNK device. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_DelayReport(UINT8 handle, UINT8 seid, UINT16 delay) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB_EVT evt; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } else + /* send event to scb */ + { + evt.apidelay.hdr.seid = seid; + evt.apidelay.delay = delay; + avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt); + } + + return result; +} + +/******************************************************************************* +** +** Function AVDT_OpenReq +** +** Description This function initiates a connection to the AVDTP service +** on the peer device, if not already present, and connects +** to a stream endpoint on a peer device. When the connection +** is completed, an AVDT_OPEN_CFM_EVT is sent to the +** application via the control callback function for this handle. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_OpenReq(UINT8 handle, BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg) +{ + tAVDT_CCB *p_ccb = NULL; + tAVDT_SCB *p_scb = NULL; + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB_EVT evt; + + /* verify SEID */ + if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX)) { + result = AVDT_BAD_PARAMS; + } + /* map handle to scb */ + else if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } + /* find channel control block for this bd addr; if none, allocate one */ + else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) { + if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL) { + /* could not allocate channel control block */ + result = AVDT_NO_RESOURCES; + } + } + + /* send event to scb */ + if (result == AVDT_SUCCESS) { + evt.msg.config_cmd.hdr.seid = seid; + evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); + evt.msg.config_cmd.int_seid = handle; + evt.msg.config_cmd.p_cfg = p_cfg; + avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_ConfigRsp +** +** Description Respond to a configure request from the peer device. This +** function must be called if the application receives an +** AVDT_CONFIG_IND_EVT through its control callback. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_ConfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category) +{ + tAVDT_SCB *p_scb; + tAVDT_SCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + UINT8 event_code; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } + /* handle special case when this function is called but peer has not send + ** a configuration cmd; ignore and return error result + */ + else if (!p_scb->in_use) { + result = AVDT_BAD_HANDLE; + } + /* send event to scb */ + else { + evt.msg.hdr.err_code = error_code; + evt.msg.hdr.err_param = category; + evt.msg.hdr.label = label; + if (error_code == 0) { + event_code = AVDT_SCB_API_SETCONFIG_RSP_EVT; + } else { + event_code = AVDT_SCB_API_SETCONFIG_REJ_EVT; + } + avdt_scb_event(p_scb, event_code, &evt); + } + + return result; +} + +/******************************************************************************* +** +** Function AVDT_StartReq +** +** Description Start one or more stream endpoints. This initiates the +** transfer of media packets for the streams. All stream +** endpoints must previously be opened. When the streams +** are started, an AVDT_START_CFM_EVT is sent to the +** application via the control callback function for each stream. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_StartReq(UINT8 *p_handles, UINT8 num_handles) +{ + tAVDT_SCB *p_scb = NULL; + tAVDT_CCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + int i; + + if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { + result = AVDT_BAD_PARAMS; + } else { + /* verify handles */ + for (i = 0; i < num_handles; i++) { + if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL) { + result = AVDT_BAD_HANDLE; + break; + } + } + } + + if (result == AVDT_SUCCESS) { + if (p_scb->p_ccb == NULL) { + result = AVDT_BAD_HANDLE; + } else { + /* send event to ccb */ + memcpy(evt.msg.multi.seid_list, p_handles, num_handles); + evt.msg.multi.num_seps = num_handles; + avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_START_REQ_EVT, &evt); + } + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_SuspendReq +** +** Description Suspend one or more stream endpoints. This suspends the +** transfer of media packets for the streams. All stream +** endpoints must previously be open and started. When the +** streams are suspended, an AVDT_SUSPEND_CFM_EVT is sent to +** the application via the control callback function for +** each stream. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_SuspendReq(UINT8 *p_handles, UINT8 num_handles) +{ + tAVDT_SCB *p_scb = NULL; + tAVDT_CCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + int i; + + if ((num_handles == 0) || (num_handles > AVDT_NUM_SEPS)) { + result = AVDT_BAD_PARAMS; + } else { + /* verify handles */ + for (i = 0; i < num_handles; i++) { + if ((p_scb = avdt_scb_by_hdl(p_handles[i])) == NULL) { + result = AVDT_BAD_HANDLE; + break; + } + } + } + + if (result == AVDT_SUCCESS) { + if (p_scb->p_ccb == NULL) { + result = AVDT_BAD_HANDLE; + } else { + /* send event to ccb */ + memcpy(evt.msg.multi.seid_list, p_handles, num_handles); + evt.msg.multi.num_seps = num_handles; + avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_API_SUSPEND_REQ_EVT, &evt); + } + } + + return result; +} + +/******************************************************************************* +** +** Function AVDT_CloseReq +** +** Description Close a stream endpoint. This stops the transfer of media +** packets and closes the transport channel associated with +** this stream endpoint. When the stream is closed, an +** AVDT_CLOSE_CFM_EVT is sent to the application via the +** control callback function for this handle. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_CloseReq(UINT8 handle) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } else + /* send event to scb */ + { + avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL); + } + + return result; +} + +/******************************************************************************* +** +** Function AVDT_ReconfigReq +** +** Description Reconfigure a stream endpoint. This allows the application +** to change the codec or content protection capabilities of +** a stream endpoint after it has been opened. This function +** can only be called if the stream is opened but not started +** or if the stream has been suspended. When the procedure +** is completed, an AVDT_RECONFIG_CFM_EVT is sent to the +** application via the control callback function for this handle. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_ReconfigReq(UINT8 handle, tAVDT_CFG *p_cfg) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB_EVT evt; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } + /* send event to scb */ + else { + /* force psc_mask to zero */ + p_cfg->psc_mask = 0; + + evt.msg.reconfig_cmd.p_cfg = p_cfg; + avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_REQ_EVT, &evt); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_ReconfigRsp +** +** Description Respond to a reconfigure request from the peer device. +** This function must be called if the application receives +** an AVDT_RECONFIG_IND_EVT through its control callback. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_ReconfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category) +{ + tAVDT_SCB *p_scb; + tAVDT_SCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } + /* send event to scb */ + else { + evt.msg.hdr.err_code = error_code; + evt.msg.hdr.err_param = category; + evt.msg.hdr.label = label; + avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, &evt); + } + + return result; +} + +/******************************************************************************* +** +** Function AVDT_SecurityReq +** +** Description Send a security request to the peer device. When the +** security procedure is completed, an AVDT_SECURITY_CFM_EVT +** is sent to the application via the control callback function +** for this handle. (Please note that AVDTP security procedures +** are unrelated to Bluetooth link level security.) +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_SecurityReq(UINT8 handle, UINT8 *p_data, UINT16 len) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB_EVT evt; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } + /* send event to scb */ + else { + evt.msg.security_rsp.p_data = p_data; + evt.msg.security_rsp.len = len; + avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_REQ_EVT, &evt); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_SecurityRsp +** +** Description Respond to a security request from the peer device. +** This function must be called if the application receives +** an AVDT_SECURITY_IND_EVT through its control callback. +** (Please note that AVDTP security procedures are unrelated +** to Bluetooth link level security.) +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_SecurityRsp(UINT8 handle, UINT8 label, UINT8 error_code, + UINT8 *p_data, UINT16 len) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + tAVDT_SCB_EVT evt; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } + /* send event to scb */ + else { + evt.msg.security_rsp.hdr.err_code = error_code; + evt.msg.security_rsp.hdr.label = label; + evt.msg.security_rsp.p_data = p_data; + evt.msg.security_rsp.len = len; + avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, &evt); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_WriteReqOpt +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC. +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteReq(). If the applications calls +** AVDT_WriteReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT +** or AVDT_START_IND_EVT. +** +** The application passes the packet using the BT_HDR structure. +** This structure is described in section 2.1. The offset +** field must be equal to or greater than AVDT_MEDIA_OFFSET +** (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used). +** This allows enough space in the buffer for the L2CAP and +** AVDTP headers. +** +** The memory pointed to by p_pkt must be a GKI buffer +** allocated by the application. This buffer will be freed +** by the protocol stack; the application must not free +** this buffer. +** +** The opt parameter allows passing specific options like: +** - NO_RTP : do not add the RTP header to buffer +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_WriteReqOpt(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt, tAVDT_DATA_OPT_MASK opt) +{ + tAVDT_SCB *p_scb; + tAVDT_SCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } else { + evt.apiwrite.p_buf = p_pkt; + evt.apiwrite.time_stamp = time_stamp; + evt.apiwrite.m_pt = m_pt; + evt.apiwrite.opt = opt; +#if AVDT_MULTIPLEXING == TRUE + GKI_init_q (&evt.apiwrite.frag_q); +#endif + avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt); + } + + return result; +} + +/******************************************************************************* +** +** Function AVDT_WriteReq +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC. +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteReq(). If the applications calls +** AVDT_WriteReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT +** or AVDT_START_IND_EVT. +** +** The application passes the packet using the BT_HDR structure. +** This structure is described in section 2.1. The offset +** field must be equal to or greater than AVDT_MEDIA_OFFSET. +** This allows enough space in the buffer for the L2CAP and +** AVDTP headers. +** +** The memory pointed to by p_pkt must be a GKI buffer +** allocated by the application. This buffer will be freed +** by the protocol stack; the application must not free +** this buffer. +** +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_WriteReq(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt) +{ + return AVDT_WriteReqOpt(handle, p_pkt, time_stamp, m_pt, AVDT_DATA_OPT_NONE); +} + +/******************************************************************************* +** +** Function AVDT_ConnectReq +** +** Description This function initiates an AVDTP signaling connection +** to the peer device. When the connection is completed, an +** AVDT_CONNECT_IND_EVT is sent to the application via its +** control callback function. If the connection attempt fails +** an AVDT_DISCONNECT_IND_EVT is sent. The security mask +** parameter overrides the outgoing security mask set in +** AVDT_Register(). +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_ConnectReq(BD_ADDR bd_addr, UINT8 sec_mask, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB *p_ccb = NULL; + UINT16 result = AVDT_SUCCESS; + tAVDT_CCB_EVT evt; + + /* find channel control block for this bd addr; if none, allocate one */ + if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) { + if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL) { + /* could not allocate channel control block */ + result = AVDT_NO_RESOURCES; + } + } else if (p_ccb->ll_opened == FALSE) { + AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening"); + + /* ccb was already allocated for the incoming signalling. */ + result = AVDT_BUSY; + } + + if (result == AVDT_SUCCESS) { + /* send event to ccb */ + evt.connect.p_cback = p_cback; + evt.connect.sec_mask = sec_mask; + avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_DisconnectReq +** +** Description This function disconnect an AVDTP signaling connection +** to the peer device. When disconnected an +** AVDT_DISCONNECT_IND_EVT is sent to the application via its +** control callback function. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +UINT16 AVDT_DisconnectReq(BD_ADDR bd_addr, tAVDT_CTRL_CBACK *p_cback) +{ + tAVDT_CCB *p_ccb = NULL; + UINT16 result = AVDT_SUCCESS; + tAVDT_CCB_EVT evt; + + /* find channel control block for this bd addr; if none, error */ + if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) { + result = AVDT_BAD_PARAMS; + } + + if (result == AVDT_SUCCESS) { + /* send event to ccb */ + evt.disconnect.p_cback = p_cback; + avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCONNECT_REQ_EVT, &evt); + } + return result; +} + +/******************************************************************************* +** +** Function AVDT_GetL2CapChannel +** +** Description Get the L2CAP CID used by the handle. +** +** Returns CID if successful, otherwise 0. +** +*******************************************************************************/ +UINT16 AVDT_GetL2CapChannel(UINT8 handle) +{ + tAVDT_SCB *p_scb; + tAVDT_CCB *p_ccb; + UINT8 tcid; + UINT16 lcid = 0; + + /* map handle to scb */ + if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) + && ((p_ccb = p_scb->p_ccb) != NULL)) { + /* get tcid from type, scb */ + tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb); + + lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; + } + + return (lcid); +} + +/******************************************************************************* +** +** Function AVDT_GetSignalChannel +** +** Description Get the L2CAP CID used by the signal channel of the given handle. +** +** Returns CID if successful, otherwise 0. +** +*******************************************************************************/ +UINT16 AVDT_GetSignalChannel(UINT8 handle, BD_ADDR bd_addr) +{ + tAVDT_SCB *p_scb; + tAVDT_CCB *p_ccb; + UINT8 tcid = 0; /* tcid is always 0 for signal channel */ + UINT16 lcid = 0; + + /* map handle to scb */ + if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) + && ((p_ccb = p_scb->p_ccb) != NULL)) { + lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; + } else if ((p_ccb = avdt_ccb_by_bd(bd_addr)) != NULL) { + lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; + } + + return (lcid); +} + +#if AVDT_MULTIPLEXING == TRUE +/******************************************************************************* +** +** Function AVDT_WriteDataReq +** +** Description Send a media packet to the peer device. The stream must +** be started before this function is called. Also, this +** function can only be called if the stream is a SRC. +** +** When AVDTP has sent the media packet and is ready for the +** next packet, an AVDT_WRITE_CFM_EVT is sent to the +** application via the control callback. The application must +** wait for the AVDT_WRITE_CFM_EVT before it makes the next +** call to AVDT_WriteDataReq(). If the applications calls +** AVDT_WriteDataReq() before it receives the event the packet +** will not be sent. The application may make its first call +** to AVDT_WriteDataReq() after it receives an +** AVDT_START_CFM_EVT or AVDT_START_IND_EVT. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_WriteDataReq(UINT8 handle, UINT8 *p_data, UINT32 data_len, + UINT32 time_stamp, UINT8 m_pt, UINT8 marker) +{ + + tAVDT_SCB *p_scb; + tAVDT_SCB_EVT evt; + UINT16 result = AVDT_SUCCESS; + + do { + /* check length of media frame */ + if (data_len > AVDT_MAX_MEDIA_SIZE) { + result = AVDT_BAD_PARAMS; + break; + } + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + break; + } + AVDT_TRACE_WARNING("mux_tsid_media:%d\n", p_scb->curr_cfg.mux_tsid_media); + + if (p_scb->p_pkt != NULL + || p_scb->p_ccb == NULL + || !GKI_queue_is_empty(&p_scb->frag_q) + || p_scb->frag_off != 0 + || p_scb->curr_cfg.mux_tsid_media == 0) { + result = AVDT_ERR_BAD_STATE; + AVDT_TRACE_WARNING("p_scb->p_pkt=%p, p_scb->p_ccb=%p, IsQueueEmpty=%x, p_scb->frag_off=%x\n", + p_scb->p_pkt, p_scb->p_ccb, GKI_queue_is_empty(&p_scb->frag_q), p_scb->frag_off); + break; + } + evt.apiwrite.p_buf = 0; /* it will indicate using of fragments queue frag_q */ + /* create queue of media fragments */ + GKI_init_q (&evt.apiwrite.frag_q); + + /* compose fragments from media payload and put fragments into gueue */ + avdt_scb_queue_frags(p_scb, &p_data, &data_len, &evt.apiwrite.frag_q); + + if (GKI_queue_is_empty(&evt.apiwrite.frag_q)) { + AVDT_TRACE_WARNING("AVDT_WriteDataReq out of GKI buffers"); + result = AVDT_ERR_RESOURCE; + break; + } + evt.apiwrite.data_len = data_len; + evt.apiwrite.p_data = p_data; + + /* process the fragments queue */ + evt.apiwrite.time_stamp = time_stamp; + evt.apiwrite.m_pt = m_pt | (marker << 7); + avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt); + } while (0); + +#if (BT_USE_TRACES == TRUE) + if (result != AVDT_SUCCESS) { + AVDT_TRACE_WARNING("*** AVDT_WriteDataReq failed result=%d\n", result); + } +#endif + return result; +} +#endif + +#if AVDT_MULTIPLEXING == TRUE +/******************************************************************************* +** +** Function AVDT_SetMediaBuf +** +** Description Assigns buffer for media packets or forbids using of assigned +** buffer if argument p_buf is NULL. This function can only +** be called if the stream is a SNK. +** +** AVDTP uses this buffer to reassemble fragmented media packets. +** When AVDTP receives a complete media packet, it calls the +** p_media_cback assigned by AVDT_CreateStream(). +** This function can be called during callback to assign a +** different buffer for next media packet or can leave the current +** buffer for next packet. +** +** Returns AVDT_SUCCESS if successful, otherwise error. +** +*******************************************************************************/ +extern UINT16 AVDT_SetMediaBuf(UINT8 handle, UINT8 *p_buf, UINT32 buf_len) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_SUCCESS; + + /* map handle to scb */ + if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { + result = AVDT_BAD_HANDLE; + } else { + if (p_buf && p_scb->cs.p_media_cback == NULL) { + result = AVDT_NO_RESOURCES; + } else { + p_scb->p_media_buf = p_buf; + p_scb->media_buf_len = buf_len; + } + } + + return result; +} +#endif + +#if AVDT_REPORTING == TRUE +/******************************************************************************* +** +** Function AVDT_SendReport +** +** Description +** +** +** +** Returns +** +*******************************************************************************/ +UINT16 AVDT_SendReport(UINT8 handle, AVDT_REPORT_TYPE type, + tAVDT_REPORT_DATA *p_data) +{ + tAVDT_SCB *p_scb; + UINT16 result = AVDT_BAD_PARAMS; + BT_HDR *p_pkt; + tAVDT_TC_TBL *p_tbl; + UINT8 *p, *plen, *pm1, *p_end; +#if AVDT_MULTIPLEXING == TRUE + UINT8 *p_al = NULL, u; +#endif + UINT32 ssrc; + UINT16 len; + + /* map handle to scb && verify parameters */ + if (((p_scb = avdt_scb_by_hdl(handle)) != NULL) + && (p_scb->p_ccb != NULL) + && (((type == AVDT_RTCP_PT_SR) && (p_scb->cs.tsep == AVDT_TSEP_SRC)) || + ((type == AVDT_RTCP_PT_RR) && (p_scb->cs.tsep == AVDT_TSEP_SNK)) || + (type == AVDT_RTCP_PT_SDES)) ) { + result = AVDT_NO_RESOURCES; + + /* build SR - assume fit in one packet */ + p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb); + if ((p_tbl->state == AVDT_AD_ST_OPEN) && + (p_pkt = (BT_HDR *)GKI_getbuf(p_tbl->peer_mtu)) != NULL) { + p_pkt->offset = L2CAP_MIN_OFFSET; + p = (UINT8 *)(p_pkt + 1) + p_pkt->offset; +#if AVDT_MULTIPLEXING == TRUE + if (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX) { + /* Adaptation Layer header later */ + p_al = p; + p += 2; + } +#endif + pm1 = p; + *p++ = AVDT_MEDIA_OCTET1 | 1; + *p++ = type; + /* save the location for length */ + plen = p; + p += 2; + ssrc = avdt_scb_gen_ssrc(p_scb); + UINT32_TO_BE_STREAM(p, ssrc); + + switch (type) { + case AVDT_RTCP_PT_SR: /* Sender Report */ + *pm1 = AVDT_MEDIA_OCTET1; + UINT32_TO_BE_STREAM(p, p_data->sr.ntp_sec); + UINT32_TO_BE_STREAM(p, p_data->sr.ntp_frac); + UINT32_TO_BE_STREAM(p, p_data->sr.rtp_time); + UINT32_TO_BE_STREAM(p, p_data->sr.pkt_count); + UINT32_TO_BE_STREAM(p, p_data->sr.octet_count); + break; + + case AVDT_RTCP_PT_RR: /* Receiver Report */ + *p++ = p_data->rr.frag_lost; + AVDT_TRACE_API("packet_lost: %d\n", p_data->rr.packet_lost); + p_data->rr.packet_lost &= 0xFFFFFF; + AVDT_TRACE_API("packet_lost: %d\n", p_data->rr.packet_lost); + UINT24_TO_BE_STREAM(p, p_data->rr.packet_lost); + UINT32_TO_BE_STREAM(p, p_data->rr.seq_num_rcvd); + UINT32_TO_BE_STREAM(p, p_data->rr.jitter); + UINT32_TO_BE_STREAM(p, p_data->rr.lsr); + UINT32_TO_BE_STREAM(p, p_data->rr.dlsr); + break; + + case AVDT_RTCP_PT_SDES: /* Source Description */ + *p++ = AVDT_RTCP_SDES_CNAME; + len = strlen((char *)p_data->cname); + if (len > AVDT_MAX_CNAME_SIZE) { + len = AVDT_MAX_CNAME_SIZE; + } + *p++ = (UINT8)len; + BCM_STRNCPY_S((char *)p, len + 1, (char *)p_data->cname, len + 1); + p += len; + break; + } + p_end = p; + len = p - pm1 - 1; + UINT16_TO_BE_STREAM(plen, len); + +#if AVDT_MULTIPLEXING == TRUE + if (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX) { + /* Adaptation Layer header */ + p = p_al; + len++; + UINT16_TO_BE_STREAM(p_al, len ); + /* TSID, no-fragment bit and coding of length(9-bit length field) */ + u = *p; + *p = (p_scb->curr_cfg.mux_tsid_report << 3) | AVDT_ALH_LCODE_9BITM0; + if (u) { + *p |= AVDT_ALH_LCODE_9BITM1; + } + } +#endif + + /* set the actual payload length */ + p_pkt->len = p_end - p; + /* send the packet */ + if (L2CAP_DW_FAILED != avdt_ad_write_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, p_pkt)) { + result = AVDT_SUCCESS; + } + } + } + + return result; +} +#endif + +/****************************************************************************** +** +** Function AVDT_SetTraceLevel +** +** Description Sets the trace level for AVDT. If 0xff is passed, the +** current trace level is returned. +** +** Input Parameters: +** new_level: The level to set the AVDT tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new trace level or current trace level if +** the input parameter is 0xff. +** +******************************************************************************/ +UINT8 AVDT_SetTraceLevel (UINT8 new_level) +{ + if (new_level != 0xFF) { + avdt_cb.trace_level = new_level; + } + + return (avdt_cb.trace_level); +} + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_ccb.c b/components/bt/bluedroid/stack/avdt/avdt_ccb.c new file mode 100644 index 0000000000..f9821a220b --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_ccb.c @@ -0,0 +1,455 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains the channel control block state machine and + * functions which operate on the channel control block. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "gki.h" +#include "btu.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) + +/***************************************************************************** +** state machine constants and types +*****************************************************************************/ +#if AVDT_DEBUG == TRUE + +/* verbose state strings for trace */ +const char *const avdt_ccb_st_str[] = { + "CCB_IDLE_ST", + "CCB_OPENING_ST", + "CCB_OPEN_ST", + "CCB_CLOSING_ST" +}; + +/* verbose event strings for trace */ +const char *const avdt_ccb_evt_str[] = { + "API_DISCOVER_REQ_EVT", + "API_GETCAP_REQ_EVT", + "API_START_REQ_EVT", + "API_SUSPEND_REQ_EVT", + "API_DISCOVER_RSP_EVT", + "API_GETCAP_RSP_EVT", + "API_START_RSP_EVT", + "API_SUSPEND_RSP_EVT", + "API_CONNECT_REQ_EVT", + "API_DISCONNECT_REQ_EVT", + "MSG_DISCOVER_CMD_EVT", + "MSG_GETCAP_CMD_EVT", + "MSG_START_CMD_EVT", + "MSG_SUSPEND_CMD_EVT", + "MSG_DISCOVER_RSP_EVT", + "MSG_GETCAP_RSP_EVT", + "MSG_START_RSP_EVT", + "MSG_SUSPEND_RSP_EVT", + "RCVRSP_EVT", + "SENDMSG_EVT", + "RET_TOUT_EVT", + "RSP_TOUT_EVT", + "IDLE_TOUT_EVT", + "UL_OPEN_EVT", + "UL_CLOSE_EVT", + "LL_OPEN_EVT", + "LL_CLOSE_EVT", + "LL_CONG_EVT" +}; + +#endif + + +/* action function list */ +const tAVDT_CCB_ACTION avdt_ccb_action[] = { + avdt_ccb_chan_open, + avdt_ccb_chan_close, + avdt_ccb_chk_close, + avdt_ccb_hdl_discover_cmd, + avdt_ccb_hdl_discover_rsp, + avdt_ccb_hdl_getcap_cmd, + avdt_ccb_hdl_getcap_rsp, + avdt_ccb_hdl_start_cmd, + avdt_ccb_hdl_start_rsp, + avdt_ccb_hdl_suspend_cmd, + avdt_ccb_hdl_suspend_rsp, + avdt_ccb_snd_discover_cmd, + avdt_ccb_snd_discover_rsp, + avdt_ccb_snd_getcap_cmd, + avdt_ccb_snd_getcap_rsp, + avdt_ccb_snd_start_cmd, + avdt_ccb_snd_start_rsp, + avdt_ccb_snd_suspend_cmd, + avdt_ccb_snd_suspend_rsp, + avdt_ccb_clear_cmds, + avdt_ccb_cmd_fail, + avdt_ccb_free_cmd, + avdt_ccb_cong_state, + avdt_ccb_ret_cmd, + avdt_ccb_snd_cmd, + avdt_ccb_snd_msg, + avdt_ccb_set_reconn, + avdt_ccb_clr_reconn, + avdt_ccb_chk_reconn, + avdt_ccb_chk_timer, + avdt_ccb_set_conn, + avdt_ccb_set_disconn, + avdt_ccb_do_disconn, + avdt_ccb_ll_closed, + avdt_ccb_ll_opened, + avdt_ccb_dealloc +}; + +/* state table information */ +#define AVDT_CCB_ACTIONS 2 /* number of actions */ +#define AVDT_CCB_NEXT_STATE 2 /* position of next state */ +#define AVDT_CCB_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for idle state */ +const UINT8 avdt_ccb_st_idle[][AVDT_CCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST}, + /* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST}, + /* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_CHAN_OPEN, AVDT_CCB_OPENING_ST}, + /* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* UL_OPEN_EVT */ {AVDT_CCB_CHAN_OPEN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* UL_CLOSE_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* LL_OPEN_EVT */ {AVDT_CCB_LL_OPENED, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST} +}; + +/* state table for opening state */ +const UINT8 avdt_ccb_st_opening[][AVDT_CCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST}, + /* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* MSG_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* UL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST}, + /* UL_CLOSE_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST}, + /* LL_OPEN_EVT */ {AVDT_CCB_SND_CMD, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST}, + /* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_IGNORE, AVDT_CCB_OPENING_ST} +}; + +/* state table for open state */ +const UINT8 avdt_ccb_st_open[][AVDT_CCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_GETCAP_REQ_EVT */ {AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_START_REQ_EVT */ {AVDT_CCB_SND_START_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_SUSPEND_REQ_EVT */ {AVDT_CCB_SND_SUSPEND_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_DISCOVER_RSP_EVT */ {AVDT_CCB_SND_DISCOVER_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_GETCAP_RSP_EVT */ {AVDT_CCB_SND_GETCAP_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_START_RSP_EVT */ {AVDT_CCB_SND_START_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_SUSPEND_RSP_EVT */ {AVDT_CCB_SND_SUSPEND_RSP, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_CONN, AVDT_CCB_LL_OPENED, AVDT_CCB_OPEN_ST}, + /* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_SET_DISCONN, AVDT_CCB_DO_DISCONN, AVDT_CCB_CLOSING_ST}, + /* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_HDL_DISCOVER_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_HDL_GETCAP_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* MSG_START_CMD_EVT */ {AVDT_CCB_HDL_START_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_HDL_SUSPEND_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_OPEN_ST}, + /* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_OPEN_ST}, + /* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* RCVRSP_EVT */ {AVDT_CCB_FREE_CMD, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* SENDMSG_EVT */ {AVDT_CCB_SND_MSG, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* RET_TOUT_EVT */ {AVDT_CCB_RET_CMD, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* RSP_TOUT_EVT */ {AVDT_CCB_CMD_FAIL, AVDT_CCB_SND_CMD, AVDT_CCB_OPEN_ST}, + /* IDLE_TOUT_EVT */ {AVDT_CCB_CLEAR_CMDS, AVDT_CCB_CHAN_CLOSE, AVDT_CCB_CLOSING_ST}, + /* UL_OPEN_EVT */ {AVDT_CCB_CHK_TIMER, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* UL_CLOSE_EVT */ {AVDT_CCB_CHK_CLOSE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_OPEN_ST}, + /* LL_CLOSE_EVT */ {AVDT_CCB_LL_CLOSED, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* LL_CONG_EVT */ {AVDT_CCB_CONG_STATE, AVDT_CCB_SND_MSG, AVDT_CCB_OPEN_ST} +}; + +/* state table for closing state */ +const UINT8 avdt_ccb_st_closing[][AVDT_CCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_DISCOVER_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_DISCOVER_CMD, AVDT_CCB_CLOSING_ST}, + /* API_GETCAP_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SND_GETCAP_CMD, AVDT_CCB_CLOSING_ST}, + /* API_START_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* API_SUSPEND_REQ_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* API_DISCOVER_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* API_GETCAP_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* API_START_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* API_SUSPEND_RSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* API_CONNECT_REQ_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_SET_CONN, AVDT_CCB_CLOSING_ST}, + /* API_DISCONNECT_REQ_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_SET_DISCONN, AVDT_CCB_CLOSING_ST}, + /* MSG_DISCOVER_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* MSG_GETCAP_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* MSG_START_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* MSG_DISCOVER_RSP_EVT */ {AVDT_CCB_HDL_DISCOVER_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* MSG_GETCAP_RSP_EVT */ {AVDT_CCB_HDL_GETCAP_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* MSG_START_RSP_EVT */ {AVDT_CCB_HDL_START_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_CCB_HDL_SUSPEND_RSP, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* RCVRSP_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* SENDMSG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* RET_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* RSP_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* IDLE_TOUT_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* UL_OPEN_EVT */ {AVDT_CCB_SET_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* UL_CLOSE_EVT */ {AVDT_CCB_CLR_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* LL_OPEN_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST}, + /* LL_CLOSE_EVT */ {AVDT_CCB_CHK_RECONN, AVDT_CCB_IGNORE, AVDT_CCB_IDLE_ST}, + /* LL_CONG_EVT */ {AVDT_CCB_IGNORE, AVDT_CCB_IGNORE, AVDT_CCB_CLOSING_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tAVDT_CCB_ST_TBL)[AVDT_CCB_NUM_COLS]; + +/* state table */ +const tAVDT_CCB_ST_TBL avdt_ccb_st_tbl[] = { + avdt_ccb_st_idle, + avdt_ccb_st_opening, + avdt_ccb_st_open, + avdt_ccb_st_closing +}; + +/******************************************************************************* +** +** Function avdt_ccb_init +** +** Description Initialize channel control block module. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ccb_init(void) +{ + memset(&avdt_cb.ccb[0], 0, sizeof(tAVDT_CCB) * AVDT_NUM_LINKS); + avdt_cb.p_ccb_act = (tAVDT_CCB_ACTION *) avdt_ccb_action; +} + +/******************************************************************************* +** +** Function avdt_ccb_event +** +** Description State machine event handling function for ccb +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data) +{ + tAVDT_CCB_ST_TBL state_table; + UINT8 action; + int i; + +#if AVDT_DEBUG == TRUE + AVDT_TRACE_EVENT("CCB ccb=%d event=%s state=%s\n", avdt_ccb_to_idx(p_ccb), avdt_ccb_evt_str[event], avdt_ccb_st_str[p_ccb->state]); +#endif + + /* look up the state table for the current state */ + state_table = avdt_ccb_st_tbl[p_ccb->state]; + + /* set next state */ + if (p_ccb->state != state_table[event][AVDT_CCB_NEXT_STATE]) { + p_ccb->state = state_table[event][AVDT_CCB_NEXT_STATE]; + } + + /* execute action functions */ + for (i = 0; i < AVDT_CCB_ACTIONS; i++) { + if ((action = state_table[event][i]) != AVDT_CCB_IGNORE) { + (*avdt_cb.p_ccb_act[action])(p_ccb, p_data); + } else { + break; + } + } +} + + +/******************************************************************************* +** +** Function avdt_ccb_by_bd +** +** Description This lookup function finds the ccb for a BD address. +** +** +** Returns pointer to the ccb, or NULL if none found. +** +*******************************************************************************/ +tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr) +{ + tAVDT_CCB *p_ccb = &avdt_cb.ccb[0]; + int i; + + for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) { + /* if allocated ccb has matching ccb */ + if (p_ccb->allocated && (!memcmp(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN))) { + break; + } + } + + if (i == AVDT_NUM_LINKS) { + /* if no ccb found */ + p_ccb = NULL; + + AVDT_TRACE_DEBUG("No ccb for addr %02x-%02x-%02x-%02x-%02x-%02x\n", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); + } + return p_ccb; +} + +/******************************************************************************* +** +** Function avdt_ccb_alloc +** +** Description Allocate a channel control block. +** +** +** Returns pointer to the ccb, or NULL if none could be allocated. +** +*******************************************************************************/ +tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr) +{ + tAVDT_CCB *p_ccb = &avdt_cb.ccb[0]; + int i; + + for (i = 0; i < AVDT_NUM_LINKS; i++, p_ccb++) { + if (!p_ccb->allocated) { + p_ccb->allocated = TRUE; + memcpy(p_ccb->peer_addr, bd_addr, BD_ADDR_LEN); + GKI_init_q(&p_ccb->cmd_q); + GKI_init_q(&p_ccb->rsp_q); + p_ccb->timer_entry.param = (UINT32) p_ccb; + AVDT_TRACE_DEBUG("avdt_ccb_alloc %d\n", i); + break; + } + } + + if (i == AVDT_NUM_LINKS) { + /* out of ccbs */ + p_ccb = NULL; + AVDT_TRACE_WARNING("Out of ccbs"); + } + return p_ccb; +} + +/******************************************************************************* +** +** Function avdt_ccb_dealloc +** +** Description Deallocate a stream control block. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + AVDT_TRACE_DEBUG("avdt_ccb_dealloc %d\n", avdt_ccb_to_idx(p_ccb)); + btu_stop_timer(&p_ccb->timer_entry); + memset(p_ccb, 0, sizeof(tAVDT_CCB)); +} + +/******************************************************************************* +** +** Function avdt_ccb_to_idx +** +** Description Given a pointer to an ccb, return its index. +** +** +** Returns Index of ccb. +** +*******************************************************************************/ +UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb) +{ + /* use array arithmetic to determine index */ + return (UINT8) (p_ccb - avdt_cb.ccb); +} + +/******************************************************************************* +** +** Function avdt_ccb_by_idx +** +** Description Return ccb pointer based on ccb index. +** +** +** Returns pointer to the ccb, or NULL if none found. +** +*******************************************************************************/ +tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx) +{ + tAVDT_CCB *p_ccb; + + /* verify index */ + if (idx < AVDT_NUM_LINKS) { + p_ccb = &avdt_cb.ccb[idx]; + } else { + p_ccb = NULL; + AVDT_TRACE_WARNING("No ccb for idx %d\n", idx); + } + return p_ccb; +} + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c b/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c new file mode 100644 index 0000000000..8c0e04229f --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_ccb_act.c @@ -0,0 +1,1084 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains the action functions associated with the channel + * control block state machine. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "gki.h" +#include "btu.h" +#include "btm_api.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) + +/******************************************************************************* +** +** Function avdt_ccb_clear_ccb +** +** Description This function clears out certain buffers, queues, and +** other data elements of a ccb. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_ccb_clear_ccb(tAVDT_CCB *p_ccb) +{ + BT_HDR *p_buf; + + /* clear certain ccb variables */ + p_ccb->cong = FALSE; + p_ccb->ret_count = 0; + + /* free message being fragmented */ + if (p_ccb->p_curr_msg != NULL) { + GKI_freebuf(p_ccb->p_curr_msg); + p_ccb->p_curr_msg = NULL; + } + + /* free message being reassembled */ + if (p_ccb->p_rx_msg != NULL) { + GKI_freebuf(p_ccb->p_rx_msg); + p_ccb->p_rx_msg = NULL; + } + + /* clear out response queue */ + while ((p_buf = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL) { + GKI_freebuf(p_buf); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_chan_open +** +** Description This function calls avdt_ad_open_req() to +** initiate a signaling channel connection. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG); + avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT); +} + +/******************************************************************************* +** +** Function avdt_ccb_chan_close +** +** Description This function calls avdt_ad_close_req() to close a +** signaling channel connection. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + /* close the transport channel used by this CCB */ + avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL); +} + +/******************************************************************************* +** +** Function avdt_ccb_chk_close +** +** Description This function checks for active streams on this CCB. +** If there are none, it starts an idle timer. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + int i; + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + UNUSED(p_data); + + /* see if there are any active scbs associated with this ccb */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { + if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) { + break; + } + } + + /* if no active scbs start idle timer */ + if (i == AVDT_NUM_SEPS) { + btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_IDLE, avdt_cb.rcb.idle_tout); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_discover_cmd +** +** Description This function is called when a discover command is +** received from the peer. It gathers up the stream +** information for all allocated streams and initiates +** sending of a discover response. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS]; + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + int i; + + p_data->msg.discover_rsp.p_sep_info = sep_info; + p_data->msg.discover_rsp.num_seps = 0; + + /* for all allocated scbs */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { + if (p_scb->allocated) { + /* copy sep info */ + sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use; + sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1; + sep_info[p_data->msg.discover_rsp.num_seps].media_type = p_scb->cs.media_type; + sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep; + + p_data->msg.discover_rsp.num_seps++; + } + } + + /* send response */ + avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data); +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_discover_rsp +** +** Description This function is called when a discover response or +** reject is received from the peer. It calls the application +** callback function with the results. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + /* we're done with procedure */ + p_ccb->proc_busy = FALSE; + + /* call app callback with results */ + (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT, + (tAVDT_CTRL *)(&p_data->msg.discover_rsp)); +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_getcap_cmd +** +** Description This function is called when a get capabilities command +** is received from the peer. It retrieves the stream +** configuration for the requested stream and initiates +** sending of a get capabilities response. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + tAVDT_SCB *p_scb; + + /* look up scb for seid sent to us */ + p_scb = avdt_scb_by_hdl(p_data->msg.single.seid); + + p_data->msg.svccap.p_cfg = &p_scb->cs.cfg; + + avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data); +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_getcap_rsp +** +** Description This function is called with a get capabilities response +** or reject is received from the peer. It calls the +** application callback function with the results. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + /* we're done with procedure */ + p_ccb->proc_busy = FALSE; + + /* call app callback with results */ + (*p_ccb->proc_cback)(0, p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT, + (tAVDT_CTRL *)(&p_data->msg.svccap)); +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_start_cmd +** +** Description This function is called when a start command is received +** from the peer. It verifies that all requested streams +** are in the proper state. If so, it initiates sending of +** a start response. Otherwise it sends a start reject. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 err_code = 0; + + /* verify all streams in the right state */ + UINT8 seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_START, p_data->msg.multi.seid_list, + p_data->msg.multi.num_seps, &err_code); + if (seid == 0 && err_code == 0) { + /* we're ok, send response */ + avdt_ccb_event(p_ccb, AVDT_CCB_API_START_RSP_EVT, p_data); + } else { + /* not ok, send reject */ + p_data->msg.hdr.err_code = err_code; + p_data->msg.hdr.err_param = seid; + avdt_msg_send_rej(p_ccb, AVDT_SIG_START, &p_data->msg); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_start_rsp +** +** Description This function is called when a start response or reject +** is received from the peer. Using the SEIDs stored in the +** current command message, it sends a start response or start +** reject event to each SCB associated with the command. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 event; + int i; + UINT8 *p; + tAVDT_SCB *p_scb; + + /* determine rsp or rej event */ + event = (p_data->msg.hdr.err_code == 0) ? + AVDT_SCB_MSG_START_RSP_EVT : AVDT_SCB_MSG_START_REJ_EVT; + + /* get to where seid's are stashed in current cmd */ + p = (UINT8 *)(p_ccb->p_curr_cmd + 1); + + /* little trick here; length of current command equals number of streams */ + for (i = 0; i < p_ccb->p_curr_cmd->len; i++) { + if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL) { + avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg); + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_suspend_cmd +** +** Description This function is called when a suspend command is received +** from the peer. It verifies that all requested streams are +** in the proper state. If so, it initiates sending of a +** suspend response. Otherwise it sends a suspend reject. + +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 seid; + UINT8 err_code = 0; + + /* verify all streams in the right state */ + if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_SUSPEND, p_data->msg.multi.seid_list, + p_data->msg.multi.num_seps, &err_code)) == 0 && + err_code == 0) { + /* we're ok, send response */ + avdt_ccb_event(p_ccb, AVDT_CCB_API_SUSPEND_RSP_EVT, p_data); + } else { + /* not ok, send reject */ + p_data->msg.hdr.err_code = err_code; + p_data->msg.hdr.err_param = seid; + avdt_msg_send_rej(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_hdl_suspend_rsp +** +** Description This function is called when a suspend response or reject +** is received from the peer. Using the SEIDs stored in the +** current command message, it sends a suspend response or +** suspend reject event to each SCB associated with the command. +** +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 event; + int i; + UINT8 *p; + tAVDT_SCB *p_scb; + + /* determine rsp or rej event */ + event = (p_data->msg.hdr.err_code == 0) ? + AVDT_SCB_MSG_SUSPEND_RSP_EVT : AVDT_SCB_MSG_SUSPEND_REJ_EVT; + + /* get to where seid's are stashed in current cmd */ + p = (UINT8 *)(p_ccb->p_curr_cmd + 1); + + /* little trick here; length of current command equals number of streams */ + for (i = 0; i < p_ccb->p_curr_cmd->len; i++) { + if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL) { + avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg); + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_discover_cmd +** +** Description This function is called to send a discover command to the +** peer. It copies variables needed for the procedure from +** the event to the CCB. It marks the CCB as busy and then +** sends a discover command. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + /* store info in ccb struct */ + p_ccb->p_proc_data = p_data->discover.p_sep_info; + p_ccb->proc_cback = p_data->discover.p_cback; + p_ccb->proc_param = p_data->discover.num_seps; + + /* we're busy */ + p_ccb->proc_busy = TRUE; + + /* build and queue discover req */ + avdt_msg_send_cmd(p_ccb, NULL, AVDT_SIG_DISCOVER, NULL); +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_discover_rsp +** +** Description This function is called to send a discover response to +** the peer. It takes the stream information passed in the +** event and sends a discover response. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + /* send response */ + avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_getcap_cmd +** +** Description This function is called to send a get capabilities command +** to the peer. It copies variables needed for the procedure +** from the event to the CCB. It marks the CCB as busy and +** then sends a get capabilities command. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 sig_id = AVDT_SIG_GETCAP; + + /* store info in ccb struct */ + p_ccb->p_proc_data = p_data->getcap.p_cfg; + p_ccb->proc_cback = p_data->getcap.p_cback; + + /* we're busy */ + p_ccb->proc_busy = TRUE; + + /* build and queue discover req */ + if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP) { + sig_id = AVDT_SIG_GET_ALLCAP; + } + + avdt_msg_send_cmd(p_ccb, NULL, sig_id, (tAVDT_MSG *) &p_data->getcap.single); +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_getcap_rsp +** +** Description This function is called to send a get capabilities response +** to the peer. It takes the stream information passed in the +** event and sends a get capabilities response. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 sig_id = AVDT_SIG_GETCAP; + + if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP) { + sig_id = AVDT_SIG_GET_ALLCAP; + } + + /* send response */ + avdt_msg_send_rsp(p_ccb, sig_id, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_start_cmd +** +** Description This function is called to send a start command to the +** peer. It verifies that all requested streams are in the +** proper state. If so, it sends a start command. Otherwise +** send ourselves back a start reject. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + int i; + tAVDT_SCB *p_scb; + tAVDT_MSG avdt_msg; + UINT8 seid_list[AVDT_NUM_SEPS]; + + /* make copy of our seid list */ + memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps); + + /* verify all streams in the right state */ + if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list, + p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0) { + /* set peer seid list in messsage */ + avdt_scb_peer_seid_list(&p_data->msg.multi); + + /* send command */ + avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_START, &p_data->msg); + } else { + /* failed; send ourselves a reject for each stream */ + for (i = 0; i < p_data->msg.multi.num_seps; i++) { + if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL) { + avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr); + } + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_start_rsp +** +** Description This function is called to send a start response to the +** peer. It takes the stream information passed in the event +** and sends a start response. Then it sends a start event +** to the SCB for each stream. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + tAVDT_SCB *p_scb; + int i; + + /* send response message */ + avdt_msg_send_rsp(p_ccb, AVDT_SIG_START, &p_data->msg); + + /* send start event to each scb */ + for (i = 0; i < p_data->msg.multi.num_seps; i++) { + if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL) { + avdt_scb_event(p_scb, AVDT_SCB_MSG_START_CMD_EVT, NULL); + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_suspend_cmd +** +** Description This function is called to send a suspend command to the +** peer. It verifies that all requested streams are in the +** proper state. If so, it sends a suspend command. +** Otherwise it calls the callback function for each requested +** stream and sends a suspend confirmation with failure. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + int i; + tAVDT_SCB *p_scb; + tAVDT_MSG avdt_msg; + UINT8 seid_list[AVDT_NUM_SEPS]; + + /* make copy of our seid list */ + memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps); + + /* verify all streams in the right state */ + if ((avdt_msg.hdr.err_param = avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list, + p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code)) == 0) { + /* set peer seid list in messsage */ + avdt_scb_peer_seid_list(&p_data->msg.multi); + + /* send command */ + avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg); + } else { + /* failed; send ourselves a reject for each stream */ + for (i = 0; i < p_data->msg.multi.num_seps; i++) { + if ((p_scb = avdt_scb_by_hdl(seid_list[i])) != NULL) { + avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT, (tAVDT_SCB_EVT *) &avdt_msg.hdr); + } + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_suspend_rsp +** +** Description This function is called to send a suspend response to the +** peer. It takes the stream information passed in the event +** and sends a suspend response. Then it sends a suspend event +** to the SCB for each stream. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + tAVDT_SCB *p_scb; + int i; + + /* send response message */ + avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg); + + /* send start event to each scb */ + for (i = 0; i < p_data->msg.multi.num_seps; i++) { + if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL) { + avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL); + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_clear_cmds +** +** Description This function is called when the signaling channel is +** closed to clean up any pending commands. For each pending +** command in the command queue, it frees the command and +** calls the application callback function indicating failure. +** Certain CCB variables are also initialized. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + int i; + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + UINT8 err_code = AVDT_ERR_CONNECT; + UNUSED(p_data); + + /* clear the ccb */ + avdt_ccb_clear_ccb(p_ccb); + + /* clear out command queue; this is a little tricky here; we need + ** to handle the case where there is a command on deck in p_curr_cmd, + ** plus we need to clear out the queue + */ + do { + /* we know p_curr_cmd = NULL after this */ + avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code); + + /* set up next message */ + p_ccb->p_curr_cmd = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q); + + } while (p_ccb->p_curr_cmd != NULL); + + /* send a CC_CLOSE_EVT any active scbs associated with this ccb */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { + if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) { + avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL); + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_cmd_fail +** +** Description This function is called when there is a response timeout. +** The currently pending command is freed and we fake a +** reject message back to ourselves. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + tAVDT_MSG msg; + UINT8 evt; + tAVDT_SCB *p_scb; + + if (p_ccb->p_curr_cmd != NULL) { + /* set up data */ + msg.hdr.err_code = p_data->err_code; + msg.hdr.err_param = 0; + msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); + + /* pretend that we received a rej message */ + evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1]; + + if (evt & AVDT_CCB_MKR) { + avdt_ccb_event(p_ccb, (UINT8) (evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg); + } else { + /* we get the scb out of the current cmd */ + p_scb = avdt_scb_by_hdl(*((UINT8 *)(p_ccb->p_curr_cmd + 1))); + if (p_scb != NULL) { + avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg); + } + } + + GKI_freebuf(p_ccb->p_curr_cmd); + p_ccb->p_curr_cmd = NULL; + } +} + +/******************************************************************************* +** +** Function avdt_ccb_free_cmd +** +** Description This function is called when a response is received for a +** currently pending command. The command is freed. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + if (p_ccb->p_curr_cmd != NULL) { + GKI_freebuf(p_ccb->p_curr_cmd); + p_ccb->p_curr_cmd = NULL; + } +} + +/******************************************************************************* +** +** Function avdt_ccb_cong_state +** +** Description This function is called to set the congestion state for +** the CCB. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + p_ccb->cong = p_data->llcong; +} + +/******************************************************************************* +** +** Function avdt_ccb_ret_cmd +** +** Description This function is called to retransmit the currently +** pending command. The retransmission count is incremented. +** If the count reaches the maximum number of retransmissions, +** the event is treated as a response timeout. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 err_code = AVDT_ERR_TIMEOUT; + BT_HDR *p_msg; + + p_ccb->ret_count++; + if (p_ccb->ret_count == AVDT_RET_MAX) { + /* command failed */ + p_ccb->ret_count = 0; + avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code); + + /* go to next queued command */ + avdt_ccb_snd_cmd(p_ccb, p_data); + } else { + /* if command pending and we're not congested and not sending a fragment */ + if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd != NULL)) { + /* make copy of message in p_curr_cmd and send it */ + if ((p_msg = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL) { + memcpy(p_msg, p_ccb->p_curr_cmd, + (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + p_ccb->p_curr_cmd->len)); + avdt_msg_send(p_ccb, p_msg); + } + } + + /* restart timer */ + btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_cmd +** +** Description This function is called the send the next command, +** if any, in the command queue. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + BT_HDR *p_msg; + UNUSED(p_data); + + /* do we have commands to send? send next command; make sure we're clear; + ** not congested, not sending fragment, not waiting for response + */ + if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && (p_ccb->p_curr_cmd == NULL)) { + if ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->cmd_q)) != NULL) { + /* make a copy of buffer in p_curr_cmd */ + if ((p_ccb->p_curr_cmd = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) != NULL) { + memcpy(p_ccb->p_curr_cmd, p_msg, (sizeof(BT_HDR) + p_msg->offset + p_msg->len)); + + avdt_msg_send(p_ccb, p_msg); + } + } + } +} + +/******************************************************************************* +** +** Function avdt_ccb_snd_msg +** +** Description +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + BT_HDR *p_msg; + UNUSED(p_data); + + /* if not congested */ + if (!p_ccb->cong) { + /* are we sending a fragmented message? continue sending fragment */ + if (p_ccb->p_curr_msg != NULL) { + avdt_msg_send(p_ccb, NULL); + } + /* do we have responses to send? send them */ + else if (!GKI_queue_is_empty(&p_ccb->rsp_q)) { + while ((p_msg = (BT_HDR *) GKI_dequeue(&p_ccb->rsp_q)) != NULL) { + if (avdt_msg_send(p_ccb, p_msg) == TRUE) { + /* break out if congested */ + break; + } + } + } + + /* do we have commands to send? send next command */ + avdt_ccb_snd_cmd(p_ccb, NULL); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_set_reconn +** +** Description This function is called to enable a reconnect attempt when +** a channel transitions from closing to idle state. It sets +** the reconn variable to TRUE. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + p_ccb->reconn = TRUE; +} + +/******************************************************************************* +** +** Function avdt_ccb_clr_reconn +** +** Description This function is called to clear the reconn variable. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + p_ccb->reconn = FALSE; +} + +/******************************************************************************* +** +** Function avdt_ccb_chk_reconn +** +** Description This function is called to check if a reconnect attempt +** is enabled. If enabled, it sends an AVDT_CCB_UL_OPEN_EVT +** to the CCB. If disabled, the CCB is deallocated. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UINT8 err_code = AVDT_ERR_CONNECT; + UNUSED(p_data); + + if (p_ccb->reconn) { + p_ccb->reconn = FALSE; + + /* clear out ccb */ + avdt_ccb_clear_ccb(p_ccb); + + /* clear out current command, if any */ + avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT *) &err_code); + + /* reopen the signaling channel */ + avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL); + } else { + avdt_ccb_ll_closed(p_ccb, NULL); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_chk_timer +** +** Description This function stops the CCB timer if the idle timer is +** running. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + if (p_ccb->timer_entry.event == BTU_TTYPE_AVDT_CCB_IDLE) { + btu_stop_timer(&p_ccb->timer_entry); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_set_conn +** +** Description Set CCB variables associated with AVDT_ConnectReq(). +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + /* save callback */ + p_ccb->p_conn_cback = p_data->connect.p_cback; + + /* set security level */ + BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_AVDTP, p_data->connect.sec_mask, + AVDT_PSM, BTM_SEC_PROTO_AVDT, AVDT_CHAN_SIG); +} + +/******************************************************************************* +** +** Function avdt_ccb_set_disconn +** +** Description Set CCB variables associated with AVDT_DisconnectReq(). +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + /* + AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x", + p_ccb->p_conn_cback, p_data->disconnect.p_cback); + */ + /* save callback */ + if (p_data->disconnect.p_cback) { + p_ccb->p_conn_cback = p_data->disconnect.p_cback; + } +} + +/******************************************************************************* +** +** Function avdt_ccb_do_disconn +** +** Description Do action associated with AVDT_DisconnectReq(). +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + UNUSED(p_data); + + /* clear any pending commands */ + avdt_ccb_clear_cmds(p_ccb, NULL); + + /* close channel */ + avdt_ccb_chan_close(p_ccb, NULL); +} + +/******************************************************************************* +** +** Function avdt_ccb_ll_closed +** +** Description Clear commands from and deallocate CCB. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + tAVDT_CTRL_CBACK *p_cback; + BD_ADDR bd_addr; + tAVDT_CTRL avdt_ctrl; + UINT8 disc_rsn; + UNUSED(p_data); + + /* clear any pending commands */ + avdt_ccb_clear_cmds(p_ccb, NULL); + + /* save callback pointer, bd addr */ + p_cback = p_ccb->p_conn_cback; + if (!p_cback) { + p_cback = avdt_cb.p_conn_cback; + } + memcpy(bd_addr, p_ccb->peer_addr, BD_ADDR_LEN); + + disc_rsn = p_ccb->disc_rsn; + + /* dealloc ccb */ + avdt_ccb_dealloc(p_ccb, NULL); + + /* call callback */ + if (p_cback) { + avdt_ctrl.hdr.err_code = 0; + avdt_ctrl.hdr.err_param = disc_rsn; + + (*p_cback)(0, bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl); + } +} + +/******************************************************************************* +** +** Function avdt_ccb_ll_opened +** +** Description Call callback on open. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) +{ + tAVDT_CTRL avdt_ctrl; + + p_ccb->ll_opened = TRUE; + + if (!p_ccb->p_conn_cback) { + p_ccb->p_conn_cback = avdt_cb.p_conn_cback; + } + + /* call callback */ + if (p_ccb->p_conn_cback) { + avdt_ctrl.hdr.err_code = 0; + avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param; + (*p_ccb->p_conn_cback)(0, p_ccb->peer_addr, AVDT_CONNECT_IND_EVT, &avdt_ctrl); + } +} + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_l2c.c b/components/bt/bluedroid/stack/avdt/avdt_l2c.c new file mode 100644 index 0000000000..ef4609098b --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_l2c.c @@ -0,0 +1,493 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This AVDTP adaption layer module interfaces to L2CAP + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "l2c_api.h" +#include "l2cdefs.h" +#include "btm_api.h" +#include "btm_int.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) + +/* callback function declarations */ +void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id); +void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result); +void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg); +void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed); +void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result); +void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested); +void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf); + +/* L2CAP callback function structure */ +const tL2CAP_APPL_INFO avdt_l2c_appl = { + avdt_l2c_connect_ind_cback, + avdt_l2c_connect_cfm_cback, + NULL, + avdt_l2c_config_ind_cback, + avdt_l2c_config_cfm_cback, + avdt_l2c_disconnect_ind_cback, + avdt_l2c_disconnect_cfm_cback, + NULL, + avdt_l2c_data_ind_cback, + avdt_l2c_congestion_ind_cback, + NULL /* tL2CA_TX_COMPLETE_CB */ +}; + +/******************************************************************************* +** +** Function avdt_sec_check_complete_term +** +** Description The function called when Security Manager finishes +** verification of the service side connection +** +** Returns void +** +*******************************************************************************/ +static void avdt_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport, + void *p_ref_data, UINT8 res) +{ + tAVDT_CCB *p_ccb = NULL; + tL2CAP_CFG_INFO cfg; + tAVDT_TC_TBL *p_tbl; + UNUSED(p_ref_data); + + AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d\n", res); + if (!bd_addr) { + AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR"); + return; + + } + p_ccb = avdt_ccb_by_bd(bd_addr); + + p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP); + if (p_tbl == NULL) { + return; + } + + if (res == BTM_SUCCESS) { + /* Send response to the L2CAP layer. */ + L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK); + + /* store idx in LCID table, store LCID in routing table */ + avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl); + avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid; + + /* transition to configuration state */ + p_tbl->state = AVDT_AD_ST_CFG; + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = p_tbl->my_mtu; + cfg.flush_to_present = TRUE; + cfg.flush_to = p_tbl->my_flush_to; + L2CA_ConfigReq(p_tbl->lcid, &cfg); + } else { + L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK); + avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK); + } +} + +/******************************************************************************* +** +** Function avdt_sec_check_complete_orig +** +** Description The function called when Security Manager finishes +** verification of the service side connection +** +** Returns void +** +*******************************************************************************/ +static void avdt_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT trasnport, + void *p_ref_data, UINT8 res) +{ + tAVDT_CCB *p_ccb = NULL; + tL2CAP_CFG_INFO cfg; + tAVDT_TC_TBL *p_tbl; + UNUSED(p_ref_data); + + AVDT_TRACE_DEBUG("avdt_sec_check_complete_orig res: %d\n", res); + if (bd_addr) { + p_ccb = avdt_ccb_by_bd(bd_addr); + } + p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_INT); + if (p_tbl == NULL) { + return; + } + + if ( res == BTM_SUCCESS ) { + /* set channel state */ + p_tbl->state = AVDT_AD_ST_CFG; + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = p_tbl->my_mtu; + cfg.flush_to_present = TRUE; + cfg.flush_to = p_tbl->my_flush_to; + L2CA_ConfigReq(p_tbl->lcid, &cfg); + } else { + L2CA_DisconnectReq (p_tbl->lcid); + avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK); + } +} +/******************************************************************************* +** +** Function avdt_l2c_connect_ind_cback +** +** Description This is the L2CAP connect indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_connect_ind_cback(BD_ADDR bd_addr, UINT16 lcid, UINT16 psm, UINT8 id) +{ + tAVDT_CCB *p_ccb; + tAVDT_TC_TBL *p_tbl = NULL; + UINT16 result; + tL2CAP_CFG_INFO cfg; + tBTM_STATUS rc; + UNUSED(psm); + + /* do we already have a control channel for this peer? */ + if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) { + /* no, allocate ccb */ + if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL) { + /* no ccb available, reject L2CAP connection */ + result = L2CAP_CONN_NO_RESOURCES; + } else { + /* allocate and set up entry; first channel is always signaling */ + p_tbl = avdt_ad_tc_tbl_alloc(p_ccb); + p_tbl->my_mtu = avdt_cb.rcb.ctrl_mtu; + p_tbl->my_flush_to = L2CAP_DEFAULT_FLUSH_TO; + p_tbl->tcid = AVDT_CHAN_SIG; + p_tbl->lcid = lcid; + p_tbl->id = id; + p_tbl->state = AVDT_AD_ST_SEC_ACP; + p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_ACP; + + /* Check the security */ + rc = btm_sec_mx_access_request (bd_addr, AVDT_PSM, + FALSE, BTM_SEC_PROTO_AVDT, + AVDT_CHAN_SIG, + &avdt_sec_check_complete_term, NULL); + if (rc == BTM_CMD_STARTED) { + L2CA_ConnectRsp (p_ccb->peer_addr, p_tbl->id, lcid, L2CAP_CONN_PENDING, L2CAP_CONN_OK); + } + return; + } + } + /* deal with simultaneous control channel connect case */ + else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_CONN)) != NULL) { + /* reject their connection */ + result = L2CAP_CONN_NO_RESOURCES; + } + /* this must be a traffic channel; are we accepting a traffic channel + ** for this ccb? + */ + else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_MEDIA, p_ccb, AVDT_AD_ST_ACP)) != NULL) { + /* yes; proceed with connection */ + result = L2CAP_CONN_OK; + } +#if AVDT_REPORTING == TRUE + /* this must be a reporting channel; are we accepting a reporting channel + ** for this ccb? + */ + else if ((p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_REPORT, p_ccb, AVDT_AD_ST_ACP)) != NULL) { + /* yes; proceed with connection */ + result = L2CAP_CONN_OK; + } +#endif + /* else we're not listening for traffic channel; reject */ + else { + result = L2CAP_CONN_NO_PSM; + } + + /* Send L2CAP connect rsp */ + L2CA_ConnectRsp(bd_addr, id, lcid, result, 0); + + /* if result ok, proceed with connection */ + if (result == L2CAP_CONN_OK) { + /* store idx in LCID table, store LCID in routing table */ + avdt_cb.ad.lcid_tbl[lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl); + avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = lcid; + + /* transition to configuration state */ + p_tbl->state = AVDT_AD_ST_CFG; + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = p_tbl->my_mtu; + cfg.flush_to_present = TRUE; + cfg.flush_to = p_tbl->my_flush_to; + L2CA_ConfigReq(lcid, &cfg); + } +} + +/******************************************************************************* +** +** Function avdt_l2c_connect_cfm_cback +** +** Description This is the L2CAP connect confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_connect_cfm_cback(UINT16 lcid, UINT16 result) +{ + tAVDT_TC_TBL *p_tbl; + tL2CAP_CFG_INFO cfg; + tAVDT_CCB *p_ccb; + + AVDT_TRACE_DEBUG("avdt_l2c_connect_cfm_cback lcid: %d, result: %d\n", + lcid, result); + /* look up info for this channel */ + if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) { + /* if in correct state */ + if (p_tbl->state == AVDT_AD_ST_CONN) { + /* if result successful */ + if (result == L2CAP_CONN_OK) { + if (p_tbl->tcid != AVDT_CHAN_SIG) { + /* set channel state */ + p_tbl->state = AVDT_AD_ST_CFG; + + /* Send L2CAP config req */ + memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); + cfg.mtu_present = TRUE; + cfg.mtu = p_tbl->my_mtu; + cfg.flush_to_present = TRUE; + cfg.flush_to = p_tbl->my_flush_to; + L2CA_ConfigReq(lcid, &cfg); + } else { + p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); + if (p_ccb == NULL) { + result = L2CAP_CONN_NO_RESOURCES; + } else { + /* set channel state */ + p_tbl->state = AVDT_AD_ST_SEC_INT; + p_tbl->lcid = lcid; + p_tbl->cfg_flags = AVDT_L2C_CFG_CONN_INT; + + /* Check the security */ + btm_sec_mx_access_request (p_ccb->peer_addr, AVDT_PSM, + TRUE, BTM_SEC_PROTO_AVDT, + AVDT_CHAN_SIG, + &avdt_sec_check_complete_orig, NULL); + } + } + } + + /* failure; notify adaption that channel closed */ + if (result != L2CAP_CONN_OK) { + avdt_ad_tc_close_ind(p_tbl, result); + } + } + } +} + +/******************************************************************************* +** +** Function avdt_l2c_config_cfm_cback +** +** Description This is the L2CAP config confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_config_cfm_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tAVDT_TC_TBL *p_tbl; + + /* look up info for this channel */ + if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) { + p_tbl->lcid = lcid; + + /* if in correct state */ + if (p_tbl->state == AVDT_AD_ST_CFG) { + /* if result successful */ + if (p_cfg->result == L2CAP_CONN_OK) { + /* update cfg_flags */ + p_tbl->cfg_flags |= AVDT_L2C_CFG_CFM_DONE; + + /* if configuration complete */ + if (p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) { + avdt_ad_tc_open_ind(p_tbl); + } + } + /* else failure */ + else { + /* Send L2CAP disconnect req */ + L2CA_DisconnectReq(lcid); + } + } + } +} + +/******************************************************************************* +** +** Function avdt_l2c_config_ind_cback +** +** Description This is the L2CAP config indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_config_ind_cback(UINT16 lcid, tL2CAP_CFG_INFO *p_cfg) +{ + tAVDT_TC_TBL *p_tbl; + + /* look up info for this channel */ + if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) { + /* store the mtu in tbl */ + if (p_cfg->mtu_present) { + p_tbl->peer_mtu = p_cfg->mtu; + } else { + p_tbl->peer_mtu = L2CAP_DEFAULT_MTU; + } + AVDT_TRACE_DEBUG("peer_mtu: %d, lcid: x%x\n", p_tbl->peer_mtu, lcid); + + /* send L2CAP configure response */ + memset(p_cfg, 0, sizeof(tL2CAP_CFG_INFO)); + p_cfg->result = L2CAP_CFG_OK; + L2CA_ConfigRsp(lcid, p_cfg); + + /* if first config ind */ + if ((p_tbl->cfg_flags & AVDT_L2C_CFG_IND_DONE) == 0) { + /* update cfg_flags */ + p_tbl->cfg_flags |= AVDT_L2C_CFG_IND_DONE; + + /* if configuration complete */ + if (p_tbl->cfg_flags & AVDT_L2C_CFG_CFM_DONE) { + avdt_ad_tc_open_ind(p_tbl); + } + } + } +} + +/******************************************************************************* +** +** Function avdt_l2c_disconnect_ind_cback +** +** Description This is the L2CAP disconnect indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_disconnect_ind_cback(UINT16 lcid, BOOLEAN ack_needed) +{ + tAVDT_TC_TBL *p_tbl; + UINT16 disc_rsn = AVDT_DISC_RSN_NORMAL; + AVDT_TRACE_DEBUG("avdt_l2c_disconnect_ind_cback lcid: %d, ack_needed: %d\n", + lcid, ack_needed); + /* look up info for this channel */ + if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) { + if (ack_needed) { + /* send L2CAP disconnect response */ + L2CA_DisconnectRsp(lcid); + } else { + disc_rsn = AVDT_DISC_RSN_ABNORMAL; + } + + avdt_ad_tc_close_ind(p_tbl, disc_rsn); + } +} + +/******************************************************************************* +** +** Function avdt_l2c_disconnect_cfm_cback +** +** Description This is the L2CAP disconnect confirm callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_disconnect_cfm_cback(UINT16 lcid, UINT16 result) +{ + tAVDT_TC_TBL *p_tbl; + + AVDT_TRACE_DEBUG("avdt_l2c_disconnect_cfm_cback lcid: %d, result: %d\n", + lcid, result); + /* look up info for this channel */ + if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) { + avdt_ad_tc_close_ind(p_tbl, result); + } +} + +/******************************************************************************* +** +** Function avdt_l2c_congestion_ind_cback +** +** Description This is the L2CAP congestion indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_congestion_ind_cback(UINT16 lcid, BOOLEAN is_congested) +{ + tAVDT_TC_TBL *p_tbl; + + /* look up info for this channel */ + if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) { + avdt_ad_tc_cong_ind(p_tbl, is_congested); + } +} + +/******************************************************************************* +** +** Function avdt_l2c_data_ind_cback +** +** Description This is the L2CAP data indication callback function. +** +** +** Returns void +** +*******************************************************************************/ +void avdt_l2c_data_ind_cback(UINT16 lcid, BT_HDR *p_buf) +{ + tAVDT_TC_TBL *p_tbl; + + /* look up info for this channel */ + if ((p_tbl = avdt_ad_tc_tbl_by_lcid(lcid)) != NULL) { + avdt_ad_tc_data_ind(p_tbl, p_buf); + } else { /* prevent buffer leak */ + GKI_freebuf(p_buf); + } +} + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_msg.c b/components/bt/bluedroid/stack/avdt/avdt_msg.c new file mode 100644 index 0000000000..557f942637 --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_msg.c @@ -0,0 +1,1769 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains functions for parsing and building AVDTP signaling + * messages. It also contains functions called by the SCB or CCB state + * machines for sending command, response, and reject messages. It also + * contains a function that processes incoming messages and dispatches them + * to the appropriate SCB or CCB. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "gki.h" +#include "btu.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) +/***************************************************************************** +** constants +*****************************************************************************/ + +/* mask of all psc values */ +#define AVDT_MSG_PSC_MASK (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT | \ + AVDT_PSC_RECOV | AVDT_PSC_HDRCMP | AVDT_PSC_MUX) +#define AVDT_PSC_PROTECT (1<<4) /* Content Protection */ +#define AVDT_PSC_CODEC (1<<7) /* codec */ + + +/***************************************************************************** +** type definitions +*****************************************************************************/ + +/* type for message building functions */ +typedef void (*tAVDT_MSG_BLD)(UINT8 **p, tAVDT_MSG *p_msg); + +/* type for message parsing functions */ +typedef UINT8 (*tAVDT_MSG_PRS)(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); + + +/***************************************************************************** +** local function declarations +*****************************************************************************/ + +static void avdt_msg_bld_none(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_single(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_setconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_reconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_multi(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_security_cmd(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_discover_rsp(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_svccap(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_security_rsp(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_all_svccap(UINT8 **p, tAVDT_MSG *p_msg); +static void avdt_msg_bld_delay_rpt(UINT8 **p, tAVDT_MSG *p_msg); + +static UINT8 avdt_msg_prs_none(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_single(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_multi(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); +static UINT8 avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, UINT8 *p, UINT16 len); + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* table of information element minimum lengths used for parsing */ +const UINT8 avdt_msg_ie_len_min[] = { + 0, /* unused */ + AVDT_LEN_TRANS_MIN, /* media transport */ + AVDT_LEN_REPORT_MIN, /* reporting */ + AVDT_LEN_RECOV_MIN, /* recovery */ + AVDT_LEN_PROTECT_MIN, /* content protection */ + AVDT_LEN_HDRCMP_MIN, /* header compression */ + AVDT_LEN_MUX_MIN, /* multiplexing */ + AVDT_LEN_CODEC_MIN, /* codec */ + AVDT_LEN_DELAY_RPT_MIN /* delay report */ +}; + +/* table of information element minimum lengths used for parsing */ +const UINT8 avdt_msg_ie_len_max[] = { + 0, /* unused */ + AVDT_LEN_TRANS_MAX, /* media transport */ + AVDT_LEN_REPORT_MAX, /* reporting */ + AVDT_LEN_RECOV_MAX, /* recovery */ + AVDT_LEN_PROTECT_MAX, /* content protection */ + AVDT_LEN_HDRCMP_MAX, /* header compression */ + AVDT_LEN_MUX_MAX, /* multiplexing */ + AVDT_LEN_CODEC_MAX, /* codec */ + AVDT_LEN_DELAY_RPT_MAX /* delay report */ +}; + +/* table of error codes used when decoding information elements */ +const UINT8 avdt_msg_ie_err[] = { + 0, /* unused */ + AVDT_ERR_MEDIA_TRANS, /* media transport */ + AVDT_ERR_LENGTH, /* reporting */ + AVDT_ERR_RECOV_FMT, /* recovery */ + AVDT_ERR_CP_FMT, /* content protection */ + AVDT_ERR_ROHC_FMT, /* header compression */ + AVDT_ERR_MUX_FMT, /* multiplexing */ + AVDT_ERR_SERVICE, /* codec */ + AVDT_ERR_SERVICE /* delay report ?? */ +}; + +/* table of packet type minimum lengths */ +static const UINT8 avdt_msg_pkt_type_len[] = { + AVDT_LEN_TYPE_SINGLE, + AVDT_LEN_TYPE_START, + AVDT_LEN_TYPE_CONT, + AVDT_LEN_TYPE_END +}; + +/* function table for building command messages */ +const tAVDT_MSG_BLD avdt_msg_bld_cmd[] = { + avdt_msg_bld_none, /* discover */ + avdt_msg_bld_single, /* get capabilities */ + avdt_msg_bld_setconfig_cmd, /* set configuration */ + avdt_msg_bld_single, /* get configuration */ + avdt_msg_bld_reconfig_cmd, /* reconfigure */ + avdt_msg_bld_single, /* open */ + avdt_msg_bld_multi, /* start */ + avdt_msg_bld_single, /* close */ + avdt_msg_bld_multi, /* suspend */ + avdt_msg_bld_single, /* abort */ + avdt_msg_bld_security_cmd, /* security control */ + avdt_msg_bld_single, /* get all capabilities */ + avdt_msg_bld_delay_rpt /* delay report */ +}; + +/* function table for building response messages */ +const tAVDT_MSG_BLD avdt_msg_bld_rsp[] = { + avdt_msg_bld_discover_rsp, /* discover */ + avdt_msg_bld_svccap, /* get capabilities */ + avdt_msg_bld_none, /* set configuration */ + avdt_msg_bld_all_svccap, /* get configuration */ + avdt_msg_bld_none, /* reconfigure */ + avdt_msg_bld_none, /* open */ + avdt_msg_bld_none, /* start */ + avdt_msg_bld_none, /* close */ + avdt_msg_bld_none, /* suspend */ + avdt_msg_bld_none, /* abort */ + avdt_msg_bld_security_rsp, /* security control */ + avdt_msg_bld_all_svccap, /* get all capabilities */ + avdt_msg_bld_none /* delay report */ +}; + +/* function table for parsing command messages */ +const tAVDT_MSG_PRS avdt_msg_prs_cmd[] = { + avdt_msg_prs_none, /* discover */ + avdt_msg_prs_single, /* get capabilities */ + avdt_msg_prs_setconfig_cmd, /* set configuration */ + avdt_msg_prs_single, /* get configuration */ + avdt_msg_prs_reconfig_cmd, /* reconfigure */ + avdt_msg_prs_single, /* open */ + avdt_msg_prs_multi, /* start */ + avdt_msg_prs_single, /* close */ + avdt_msg_prs_multi, /* suspend */ + avdt_msg_prs_single, /* abort */ + avdt_msg_prs_security_cmd, /* security control */ + avdt_msg_prs_single, /* get all capabilities */ + avdt_msg_prs_delay_rpt /* delay report */ +}; + +/* function table for parsing response messages */ +const tAVDT_MSG_PRS avdt_msg_prs_rsp[] = { + avdt_msg_prs_discover_rsp, /* discover */ + avdt_msg_prs_svccap, /* get capabilities */ + avdt_msg_prs_none, /* set configuration */ + avdt_msg_prs_all_svccap, /* get configuration */ + avdt_msg_prs_none, /* reconfigure */ + avdt_msg_prs_none, /* open */ + avdt_msg_prs_none, /* start */ + avdt_msg_prs_none, /* close */ + avdt_msg_prs_none, /* suspend */ + avdt_msg_prs_none, /* abort */ + avdt_msg_prs_security_rsp, /* security control */ + avdt_msg_prs_all_svccap, /* get all capabilities */ + avdt_msg_prs_none /* delay report */ +}; + +/* command message-to-event lookup table */ +const UINT8 avdt_msg_cmd_2_evt[] = { + AVDT_CCB_MSG_DISCOVER_CMD_EVT + AVDT_CCB_MKR, /* discover */ + AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get capabilities */ + AVDT_SCB_MSG_SETCONFIG_CMD_EVT, /* set configuration */ + AVDT_SCB_MSG_GETCONFIG_CMD_EVT, /* get configuration */ + AVDT_SCB_MSG_RECONFIG_CMD_EVT, /* reconfigure */ + AVDT_SCB_MSG_OPEN_CMD_EVT, /* open */ + AVDT_CCB_MSG_START_CMD_EVT + AVDT_CCB_MKR, /* start */ + AVDT_SCB_MSG_CLOSE_CMD_EVT, /* close */ + AVDT_CCB_MSG_SUSPEND_CMD_EVT + AVDT_CCB_MKR, /* suspend */ + AVDT_SCB_MSG_ABORT_CMD_EVT, /* abort */ + AVDT_SCB_MSG_SECURITY_CMD_EVT, /* security control */ + AVDT_CCB_MSG_GETCAP_CMD_EVT + AVDT_CCB_MKR, /* get all capabilities */ + AVDT_SCB_MSG_DELAY_RPT_CMD_EVT /* delay report */ +}; + +/* response message-to-event lookup table */ +const UINT8 avdt_msg_rsp_2_evt[] = { + AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */ + AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */ + AVDT_SCB_MSG_SETCONFIG_RSP_EVT, /* set configuration */ + AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */ + AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */ + AVDT_SCB_MSG_OPEN_RSP_EVT, /* open */ + AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */ + AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */ + AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */ + AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */ + AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */ + AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */ + AVDT_SCB_MSG_DELAY_RPT_RSP_EVT /* delay report */ +}; + +/* reject message-to-event lookup table */ +const UINT8 avdt_msg_rej_2_evt[] = { + AVDT_CCB_MSG_DISCOVER_RSP_EVT + AVDT_CCB_MKR, /* discover */ + AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get capabilities */ + AVDT_SCB_MSG_SETCONFIG_REJ_EVT, /* set configuration */ + AVDT_SCB_MSG_GETCONFIG_RSP_EVT, /* get configuration */ + AVDT_SCB_MSG_RECONFIG_RSP_EVT, /* reconfigure */ + AVDT_SCB_MSG_OPEN_REJ_EVT, /* open */ + AVDT_CCB_MSG_START_RSP_EVT + AVDT_CCB_MKR, /* start */ + AVDT_SCB_MSG_CLOSE_RSP_EVT, /* close */ + AVDT_CCB_MSG_SUSPEND_RSP_EVT + AVDT_CCB_MKR, /* suspend */ + AVDT_SCB_MSG_ABORT_RSP_EVT, /* abort */ + AVDT_SCB_MSG_SECURITY_RSP_EVT, /* security control */ + AVDT_CCB_MSG_GETCAP_RSP_EVT + AVDT_CCB_MKR, /* get all capabilities */ + 0 /* delay report */ +}; + +/******************************************************************************* +** +** Function avdt_msg_bld_cfg +** +** Description This function builds the configuration parameters contained +** in a command or response message. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_cfg(UINT8 **p, tAVDT_CFG *p_cfg) +{ + UINT8 len; + + /* for now, just build media transport, codec, and content protection, and multiplexing */ + + /* media transport */ + if (p_cfg->psc_mask & AVDT_PSC_TRANS) { + *(*p)++ = AVDT_CAT_TRANS; + *(*p)++ = 0; /* length */ + } + +#if AVDT_REPORTING == TRUE + /* reporting transport */ + if (p_cfg->psc_mask & AVDT_PSC_REPORT) { + *(*p)++ = AVDT_CAT_REPORT; + *(*p)++ = 0; /* length */ + } +#endif + + /* codec */ + if (p_cfg->num_codec != 0) { + *(*p)++ = AVDT_CAT_CODEC; + len = p_cfg->codec_info[0] + 1; + if ( len > AVDT_CODEC_SIZE ) { + len = AVDT_CODEC_SIZE; + } + + memcpy(*p, p_cfg->codec_info, len); + *p += len; + } + + /* content protection */ + if (p_cfg->num_protect != 0) { + *(*p)++ = AVDT_CAT_PROTECT; + len = p_cfg->protect_info[0] + 1; + if ( len > AVDT_PROTECT_SIZE ) { + len = AVDT_PROTECT_SIZE; + } + + memcpy(*p, p_cfg->protect_info, len); + *p += len; + } + +#if AVDT_MULTIPLEXING == TRUE + /* multiplexing */ + if (p_cfg->psc_mask & AVDT_PSC_MUX) { + *(*p)++ = AVDT_CAT_MUX; + /* length */ + if (p_cfg->psc_mask & AVDT_PSC_RECOV) { + *(*p)++ = 7; /* frag (1) + media + report + recovery */ + } else if (p_cfg->psc_mask & AVDT_PSC_REPORT) { + *(*p)++ = 5; /* frag (1) + media + report */ + } else { + *(*p)++ = 3; /* frag (1) + media */ + } + + /* allow fragmentation */ + if (p_cfg->mux_mask & AVDT_MUX_FRAG) { + *(*p)++ = 0x80; + } else { + *(*p)++ = 0; + } + + /* media transport session */ + *(*p)++ = p_cfg->mux_tsid_media << 3; /* TSID */ + *(*p)++ = p_cfg->mux_tcid_media << 3; /* TCID */ + + if (p_cfg->psc_mask & AVDT_PSC_RECOV) { + /* reporting transport session */ + *(*p)++ = p_cfg->mux_tsid_report << 3; /* TSID */ + *(*p)++ = p_cfg->mux_tcid_report << 3; /* TCID */ + /* recovery transport session */ + *(*p)++ = p_cfg->mux_tsid_recov << 3; /* TSID */ + *(*p)++ = p_cfg->mux_tcid_recov << 3; /* TCID */ + } else if (p_cfg->psc_mask & AVDT_PSC_REPORT) { + /* reporting transport session */ + *(*p)++ = p_cfg->mux_tsid_report << 3; /* TSID */ + *(*p)++ = p_cfg->mux_tcid_report << 3; /* TCID */ + } + } +#endif + + /* delay report */ + if (p_cfg->psc_mask & AVDT_PSC_DELAY_RPT) { + *(*p)++ = AVDT_CAT_DELAY_RPT; + *(*p)++ = 0; /* length */ + } +} + +/******************************************************************************* +** +** Function avdt_msg_bld_none +** +** Description This message building function builds an empty message. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_none(UINT8 **p, tAVDT_MSG *p_msg) +{ + UNUSED(p); + UNUSED(p_msg); + return; +} + +/******************************************************************************* +** +** Function avdt_msg_bld_single +** +** Description This message building function builds a message containing +** a single SEID. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_single(UINT8 **p, tAVDT_MSG *p_msg) +{ + AVDT_MSG_BLD_SEID(*p, p_msg->single.seid); +} + +/******************************************************************************* +** +** Function avdt_msg_bld_setconfig_cmd +** +** Description This message building function builds a set configuration +** command message. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_setconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg) +{ + AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.hdr.seid); + AVDT_MSG_BLD_SEID(*p, p_msg->config_cmd.int_seid); + avdt_msg_bld_cfg(p, p_msg->config_cmd.p_cfg); +} + +/******************************************************************************* +** +** Function avdt_msg_bld_reconfig_cmd +** +** Description This message building function builds a reconfiguration +** command message. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_reconfig_cmd(UINT8 **p, tAVDT_MSG *p_msg) +{ + AVDT_MSG_BLD_SEID(*p, p_msg->reconfig_cmd.hdr.seid); + + /* force psc mask zero to build only codec and security */ + p_msg->reconfig_cmd.p_cfg->psc_mask = 0; + avdt_msg_bld_cfg(p, p_msg->reconfig_cmd.p_cfg); +} + +/******************************************************************************* +** +** Function avdt_msg_bld_multi +** +** Description This message building function builds a message containing +** multiple SEID's. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_multi(UINT8 **p, tAVDT_MSG *p_msg) +{ + int i; + + for (i = 0; i < p_msg->multi.num_seps; i++) { + AVDT_MSG_BLD_SEID(*p, p_msg->multi.seid_list[i]); + } +} + +/******************************************************************************* +** +** Function avdt_msg_bld_security_cmd +** +** Description This message building function builds a security +** command message. +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_security_cmd(UINT8 **p, tAVDT_MSG *p_msg) +{ + AVDT_MSG_BLD_SEID(*p, p_msg->security_cmd.hdr.seid); + memcpy(*p, p_msg->security_cmd.p_data, p_msg->security_cmd.len); + *p += p_msg->security_cmd.len; +} + +/******************************************************************************* +** +** Function avdt_msg_bld_delay_rpt +** +** Description This message building function builds a delay report +** command message. +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_delay_rpt(UINT8 **p, tAVDT_MSG *p_msg) +{ + AVDT_MSG_BLD_SEID(*p, p_msg->delay_rpt_cmd.hdr.seid); + UINT16_TO_BE_STREAM(*p, p_msg->delay_rpt_cmd.delay); +} + +/******************************************************************************* +** +** Function avdt_msg_bld_discover_rsp +** +** Description This message building function builds a discover +** response message. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_discover_rsp(UINT8 **p, tAVDT_MSG *p_msg) +{ + int i; + + for (i = 0; i < p_msg->discover_rsp.num_seps; i++) { + /* build discover rsp info */ + AVDT_MSG_BLD_DISC(*p, p_msg->discover_rsp.p_sep_info[i].seid, + p_msg->discover_rsp.p_sep_info[i].in_use, + p_msg->discover_rsp.p_sep_info[i].media_type, + p_msg->discover_rsp.p_sep_info[i].tsep); + } +} + +/******************************************************************************* +** +** Function avdt_msg_bld_svccap +** +** Description This message building function builds a message containing +** service capabilities parameters. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_svccap(UINT8 **p, tAVDT_MSG *p_msg) +{ + tAVDT_CFG cfg; + + /* make sure the delay report category is not reported */ + memcpy (&cfg, p_msg->svccap.p_cfg, sizeof(tAVDT_CFG)); + cfg.psc_mask &= ~AVDT_PSC_DELAY_RPT; + avdt_msg_bld_cfg(p, &cfg); +} + +/******************************************************************************* +** +** Function avdt_msg_bld_all_svccap +** +** Description This message building function builds a message containing +** service capabilities parameters. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_all_svccap(UINT8 **p, tAVDT_MSG *p_msg) +{ + avdt_msg_bld_cfg(p, p_msg->svccap.p_cfg); +} + +/******************************************************************************* +** +** Function avdt_msg_bld_security_rsp +** +** Description This message building function builds a security +** response message. +** +** +** Returns void. +** +*******************************************************************************/ +static void avdt_msg_bld_security_rsp(UINT8 **p, tAVDT_MSG *p_msg) +{ + memcpy(*p, p_msg->security_rsp.p_data, p_msg->security_rsp.len); + *p += p_msg->security_rsp.len; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_cfg +** +** Description This message parsing function parses the configuration +** parameters field of a message. +** +** +** Returns Error code or zero if no error, and element that failed +** in p_elem. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_cfg(tAVDT_CFG *p_cfg, UINT8 *p, UINT16 len, UINT8 *p_elem, UINT8 sig_id) +{ + UINT8 *p_end; + UINT8 elem = 0; + UINT8 elem_len; + UINT8 tmp; + UINT8 err = 0; + UINT8 protect_offset = 0; + + if (!p_cfg) { + AVDT_TRACE_ERROR ("not expecting this cfg"); + return AVDT_ERR_BAD_STATE; + } + + p_cfg->psc_mask = 0; + p_cfg->num_codec = 0; + p_cfg->num_protect = 0; +#if AVDT_MULTIPLEXING == TRUE + p_cfg->mux_mask = 0; +#endif + + /* while there is still data to parse */ + p_end = p + len; + while ((p < p_end) && (err == 0)) { + /* verify overall length */ + if ((p_end - p) < AVDT_LEN_CFG_MIN) { + err = AVDT_ERR_PAYLOAD; + break; + } + + /* get and verify info elem id, length */ + elem = *p++; + elem_len = *p++; + + if ((elem == 0) || (elem > AVDT_CAT_MAX_CUR)) { + /* this may not be really bad. + * It may be a service category that is too new for us. + * allow these to be parsed without reporting an error. + * If this is a "capability" (as in GetCapRsp & GetConfigRsp), this is filtered out. + * If this is a Configuration (as in SetConfigCmd & ReconfigCmd), + * this will be marked as an error in the caller of this function */ + if ((sig_id == AVDT_SIG_SETCONFIG) || (sig_id == AVDT_SIG_RECONFIG)) { + /* Cannot accept unknown category. */ + err = AVDT_ERR_CATEGORY; + break; + } else { /* GETCAP or GET_ALLCAP */ + /* Skip unknown categories. */ + p += elem_len; + AVDT_TRACE_DEBUG("skipping unknown service category=%d len: %d\n", elem, elem_len); + continue; + } + } + + if ((elem_len > avdt_msg_ie_len_max[elem]) || + (elem_len < avdt_msg_ie_len_min[elem])) { + err = avdt_msg_ie_err[elem]; + break; + } + + /* add element to psc mask, but mask out codec or protect */ + p_cfg->psc_mask |= (1 << elem); + AVDT_TRACE_DEBUG("elem=%d elem_len: %d psc_mask=0x%x\n", elem, elem_len, p_cfg->psc_mask); + + /* parse individual information elements with additional parameters */ + switch (elem) { + case AVDT_CAT_RECOV: + p_cfg->recov_type = *p++; + p_cfg->recov_mrws = *p++; + p_cfg->recov_mnmp = *p++; + if (p_cfg->recov_type != AVDT_RECOV_RFC2733) { + err = AVDT_ERR_RECOV_TYPE; + } else if ((p_cfg->recov_mrws < AVDT_RECOV_MRWS_MIN) || + (p_cfg->recov_mrws > AVDT_RECOV_MRWS_MAX) || + (p_cfg->recov_mnmp < AVDT_RECOV_MNMP_MIN) || + (p_cfg->recov_mnmp > AVDT_RECOV_MNMP_MAX)) { + err = AVDT_ERR_RECOV_FMT; + } + break; + + case AVDT_CAT_PROTECT: + p_cfg->psc_mask &= ~AVDT_PSC_PROTECT; + if ((elem_len + protect_offset) < AVDT_PROTECT_SIZE) { + p_cfg->num_protect++; + p_cfg->protect_info[protect_offset] = elem_len; + protect_offset++; + memcpy(&p_cfg->protect_info[protect_offset], p, elem_len); + protect_offset += elem_len; + } + p += elem_len; + break; + + case AVDT_CAT_HDRCMP: + p_cfg->hdrcmp_mask = *p++; + break; + +#if AVDT_MULTIPLEXING == TRUE + case AVDT_CAT_MUX: + /* verify length */ + AVDT_TRACE_WARNING("psc_mask=0x%x elem_len=%d\n", p_cfg->psc_mask, elem_len); + if ( ((0 == (p_cfg->psc_mask & (AVDT_PSC_RECOV | AVDT_PSC_REPORT))) && (elem_len != 3)) + || (((p_cfg->psc_mask & AVDT_PSC_REPORT) && !(p_cfg->psc_mask & AVDT_PSC_RECOV)) + && (elem_len != 5)) + || ((!(p_cfg->psc_mask & AVDT_PSC_REPORT) && (p_cfg->psc_mask & AVDT_PSC_RECOV)) + && (elem_len != 5)) + || (((p_cfg->psc_mask & AVDT_PSC_REPORT) && (p_cfg->psc_mask & AVDT_PSC_RECOV)) + && (elem_len != 7)) ) { + err = AVDT_ERR_MUX_FMT; + break; + } + + /* parse fragmentation */ + p_cfg->mux_mask = *p++ & (UINT8)AVDT_MUX_FRAG; + + /* parse TSIDs and TCIDs */ + if (--elem_len) { + p_cfg->mux_tsid_media = (*p++) >> 3; + } else { + break; + } + + if (--elem_len) { + p_cfg->mux_tcid_media = (*p++) >> 3; + } else { + break; + } + + if (--elem_len) { + p_cfg->mux_tsid_report = (*p++) >> 3; + } else { + break; + } + + if (--elem_len) { + p_cfg->mux_tcid_report = (*p++) >> 3; + } else { + break; + } + + if (--elem_len) { + p_cfg->mux_tsid_recov = (*p++) >> 3; + } else { + break; + } + + if (--elem_len) { + p_cfg->mux_tcid_recov = (*p++) >> 3; + } else { + break; + } + break; +#endif + + case AVDT_CAT_CODEC: + p_cfg->psc_mask &= ~AVDT_PSC_CODEC; + tmp = elem_len; + if (elem_len >= AVDT_CODEC_SIZE) { + tmp = AVDT_CODEC_SIZE - 1; + } + p_cfg->num_codec++; + p_cfg->codec_info[0] = elem_len; + memcpy(&p_cfg->codec_info[1], p, tmp); + p += elem_len; + break; + + case AVDT_CAT_DELAY_RPT: + break; + + default: + p += elem_len; + break; + } /* switch */ + } /* while ! err, !end*/ + *p_elem = elem; + AVDT_TRACE_DEBUG("err=0x%x, elem:0x%x psc_mask=0x%x\n", err, elem, p_cfg->psc_mask); + + return err; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_none +** +** Description This message parsing function parses a message with no parameters. + +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_none(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + UNUSED(p_msg); + UNUSED(p); + UNUSED(len); + return 0; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_single +** +** Description This message parsing function parses a message with a +** single SEID. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_single(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + UINT8 err = 0; + + /* verify len */ + if (len != AVDT_LEN_SINGLE) { + err = AVDT_ERR_LENGTH; + } else { + AVDT_MSG_PRS_SEID(p, p_msg->single.seid); + + if (avdt_scb_by_hdl(p_msg->single.seid) == NULL) { + err = AVDT_ERR_SEID; + } + } + return err; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_setconfig_cmd +** +** Description This message parsing function parses a set configuration +** command message. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_setconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + UINT8 err = 0; + + p_msg->hdr.err_param = 0; + + /* verify len */ + if (len < AVDT_LEN_SETCONFIG_MIN) { + err = AVDT_ERR_LENGTH; + } else { + /* get seids */ + AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.hdr.seid); + if (avdt_scb_by_hdl(p_msg->config_cmd.hdr.seid) == NULL) { + err = AVDT_ERR_SEID; + } + + AVDT_MSG_PRS_SEID(p, p_msg->config_cmd.int_seid); + if ((p_msg->config_cmd.int_seid < AVDT_SEID_MIN) || + (p_msg->config_cmd.int_seid > AVDT_SEID_MAX)) { + err = AVDT_ERR_SEID; + } + } + + if (!err) { + /* parse configuration parameters */ + len -= 2; + err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_SETCONFIG); + + if (!err) { + /* verify protocol service capabilities are supported */ + if (((p_msg->config_cmd.p_cfg->psc_mask & (~AVDT_PSC)) != 0) || + (p_msg->config_cmd.p_cfg->num_codec == 0)) { + err = AVDT_ERR_INVALID_CAP; + } + } + } + + return err; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_reconfig_cmd +** +** Description This message parsing function parses a reconfiguration +** command message. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_reconfig_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + UINT8 err = 0; + + p_msg->hdr.err_param = 0; + + /* verify len */ + if (len < AVDT_LEN_RECONFIG_MIN) { + err = AVDT_ERR_LENGTH; + } else { + /* get seid */ + AVDT_MSG_PRS_SEID(p, p_msg->reconfig_cmd.hdr.seid); + if (avdt_scb_by_hdl(p_msg->reconfig_cmd.hdr.seid) == NULL) { + err = AVDT_ERR_SEID; + } else { + /* parse config parameters */ + len--; + err = avdt_msg_prs_cfg(p_msg->config_cmd.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_RECONFIG); + + /* verify no protocol service capabilities in parameters */ + if (!err) { + AVDT_TRACE_DEBUG("avdt_msg_prs_reconfig_cmd psc_mask=0x%x/0x%x\n", p_msg->config_cmd.p_cfg->psc_mask, AVDT_MSG_PSC_MASK); + if ((p_msg->config_cmd.p_cfg->psc_mask != 0) || + (p_msg->config_cmd.p_cfg->num_codec == 0 && p_msg->config_cmd.p_cfg->num_protect == 0)) { + err = AVDT_ERR_INVALID_CAP; + } + } + } + } + return err; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_multi +** +** Description This message parsing function parses a message containing +** multiple SEID's. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_multi(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + int i; + UINT8 err = 0; + + p_msg->hdr.err_param = 0; + + /* verify len */ + if (len < AVDT_LEN_MULTI_MIN || (len > AVDT_NUM_SEPS)) { + err = AVDT_ERR_LENGTH; + } else { + /* get and verify all seps */ + for (i = 0; i < len; i++) { + AVDT_MSG_PRS_SEID(p, p_msg->multi.seid_list[i]); + if (avdt_scb_by_hdl(p_msg->multi.seid_list[i]) == NULL) { + err = AVDT_ERR_SEID; + p_msg->hdr.err_param = p_msg->multi.seid_list[i]; + break; + } + } + p_msg->multi.num_seps = (UINT8)i; + } + + return err; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_security_cmd +** +** Description This message parsing function parses a security +** command message. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_security_cmd(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + UINT8 err = 0; + + /* verify len */ + if (len < AVDT_LEN_SECURITY_MIN) { + err = AVDT_ERR_LENGTH; + } else { + /* get seid */ + AVDT_MSG_PRS_SEID(p, p_msg->security_cmd.hdr.seid); + if (avdt_scb_by_hdl(p_msg->security_cmd.hdr.seid) == NULL) { + err = AVDT_ERR_SEID; + } else { + p_msg->security_cmd.p_data = p; + p_msg->security_cmd.len = len - 1; + } + } + return err; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_discover_rsp +** +** Description This message parsing function parses a discover +** response message. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_discover_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + int i; + UINT8 err = 0; + + /* determine number of seps; seps in msg is len/2, but set to minimum + ** of seps app has supplied memory for and seps in msg + */ + if (p_msg->discover_rsp.num_seps > (len / 2)) { + p_msg->discover_rsp.num_seps = (len / 2); + } + + /* parse out sep info */ + for (i = 0; i < p_msg->discover_rsp.num_seps; i++) { + /* parse discover rsp info */ + AVDT_MSG_PRS_DISC(p, p_msg->discover_rsp.p_sep_info[i].seid, + p_msg->discover_rsp.p_sep_info[i].in_use, + p_msg->discover_rsp.p_sep_info[i].media_type, + p_msg->discover_rsp.p_sep_info[i].tsep); + + /* verify that seid is valid */ + if ((p_msg->discover_rsp.p_sep_info[i].seid < AVDT_SEID_MIN) || + (p_msg->discover_rsp.p_sep_info[i].seid > AVDT_SEID_MAX)) { + err = AVDT_ERR_SEID; + break; + } + } + + return err; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_svccap +** +** Description This message parsing function parses a message containing +** service capabilities parameters. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + /* parse parameters */ + UINT8 err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GETCAP); + if (p_msg->svccap.p_cfg) { + p_msg->svccap.p_cfg->psc_mask &= AVDT_LEG_PSC; + } + + return (err); +} + +/******************************************************************************* +** +** Function avdt_msg_prs_all_svccap +** +** Description This message parsing function parses a message containing +** service capabilities parameters. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_all_svccap(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + UINT8 err = avdt_msg_prs_cfg(p_msg->svccap.p_cfg, p, len, &p_msg->hdr.err_param, AVDT_SIG_GET_ALLCAP); + if (p_msg->svccap.p_cfg) { + p_msg->svccap.p_cfg->psc_mask &= AVDT_MSG_PSC_MASK; + } + return (err); +} + +/******************************************************************************* +** +** Function avdt_msg_prs_security_rsp +** +** Description This message parsing function parsing a security +** response message. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_security_rsp(tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + p_msg->security_rsp.p_data = p; + p_msg->security_rsp.len = len; + + return 0; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_rej +** +** Description +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_rej(tAVDT_MSG *p_msg, UINT8 *p, UINT8 sig) +{ + if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG)) { + p_msg->hdr.err_param = *p++; + p_msg->hdr.err_code = *p; + } else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND)) { + AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param); + p_msg->hdr.err_code = *p; + } else { + p_msg->hdr.err_code = *p; + } + + return 0; +} + +/******************************************************************************* +** +** Function avdt_msg_prs_delay_rpt +** +** Description This message parsing function parses a security +** command message. +** +** +** Returns Error code or zero if no error. +** +*******************************************************************************/ +static UINT8 avdt_msg_prs_delay_rpt (tAVDT_MSG *p_msg, UINT8 *p, UINT16 len) +{ + UINT8 err = 0; + + /* verify len */ + if (len != AVDT_LEN_DELAY_RPT) { + AVDT_TRACE_WARNING("avdt_msg_prs_delay_rpt expected len: %u got: %u\n", AVDT_LEN_DELAY_RPT, len); + err = AVDT_ERR_LENGTH; + } else { + /* get seid */ + AVDT_MSG_PRS_SEID (p, p_msg->delay_rpt_cmd.hdr.seid); + + if (avdt_scb_by_hdl(p_msg->delay_rpt_cmd.hdr.seid) == NULL) { + err = AVDT_ERR_SEID; + } else { + BE_STREAM_TO_UINT16 (p_msg->delay_rpt_cmd.delay, p); + AVDT_TRACE_DEBUG("avdt_msg_prs_delay_rpt delay: %u\n", p_msg->delay_rpt_cmd.delay); + } + } + return err; +} + + +/******************************************************************************* +** +** Function avdt_msg_send +** +** Description Send, and if necessary fragment the next message. +** +** +** Returns Congested state; TRUE if CCB congested, FALSE if not. +** +*******************************************************************************/ +BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg) +{ + UINT16 curr_msg_len; + UINT8 pkt_type; + UINT8 hdr_len; + tAVDT_TC_TBL *p_tbl; + BT_HDR *p_buf; + UINT8 *p; + UINT8 label; + UINT8 msg; + UINT8 sig; + UINT8 nosp = 0; /* number of subsequent packets */ + + /* look up transport channel table entry to get peer mtu */ + p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_SIG, p_ccb, NULL); + + /* set the current message if there is a message passed in */ + if (p_msg != NULL) { + p_ccb->p_curr_msg = p_msg; + } + + /* store copy of curr_msg->len */ + curr_msg_len = p_ccb->p_curr_msg->len; + + /* while not congested and we haven't sent it all */ + while ((!p_ccb->cong) && (p_ccb->p_curr_msg != NULL)) { + /* check what kind of message we've got here; we are using the offset + ** to indicate that a message is being fragmented + */ + + /* if message isn't being fragmented and it fits in mtu */ + if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) && + (p_ccb->p_curr_msg->len <= p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE)) { + pkt_type = AVDT_PKT_TYPE_SINGLE; + hdr_len = AVDT_LEN_TYPE_SINGLE; + p_buf = p_ccb->p_curr_msg; + } + /* if message isn't being fragmented and it doesn't fit in mtu */ + else if ((p_ccb->p_curr_msg->offset == AVDT_MSG_OFFSET) && + (p_ccb->p_curr_msg->len > p_tbl->peer_mtu - AVDT_LEN_TYPE_SINGLE)) { + pkt_type = AVDT_PKT_TYPE_START; + hdr_len = AVDT_LEN_TYPE_START; + nosp = (p_ccb->p_curr_msg->len + AVDT_LEN_TYPE_START - p_tbl->peer_mtu) / + (p_tbl->peer_mtu - 1) + 2; + + /* get a new buffer for fragment we are sending */ + if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) == NULL) { + /* do we even want to try and recover from this? could do so + by setting retransmission timer */ + return TRUE; + } + + /* copy portion of data from current message to new buffer */ + p_buf->offset = L2CAP_MIN_OFFSET + hdr_len; + p_buf->len = p_tbl->peer_mtu - hdr_len; + memcpy((UINT8 *)(p_buf + 1) + p_buf->offset, + (UINT8 *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len); + } + /* if message is being fragmented and remaining bytes don't fit in mtu */ + else if ((p_ccb->p_curr_msg->offset > AVDT_MSG_OFFSET) && + (p_ccb->p_curr_msg->len > (p_tbl->peer_mtu - AVDT_LEN_TYPE_CONT))) { + pkt_type = AVDT_PKT_TYPE_CONT; + hdr_len = AVDT_LEN_TYPE_CONT; + + /* get a new buffer for fragment we are sending */ + if ((p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID)) == NULL) { + /* do we even want to try and recover from this? could do so + by setting retransmission timer */ + return TRUE; + } + + /* copy portion of data from current message to new buffer */ + p_buf->offset = L2CAP_MIN_OFFSET + hdr_len; + p_buf->len = p_tbl->peer_mtu - hdr_len; + memcpy((UINT8 *)(p_buf + 1) + p_buf->offset, + (UINT8 *)(p_ccb->p_curr_msg + 1) + p_ccb->p_curr_msg->offset, p_buf->len); + } + /* if message is being fragmented and remaining bytes do fit in mtu */ + else { + pkt_type = AVDT_PKT_TYPE_END; + hdr_len = AVDT_LEN_TYPE_END; + p_buf = p_ccb->p_curr_msg; + } + + /* label, sig id, msg type are in hdr of p_curr_msg */ + label = AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_msg->layer_specific); + msg = AVDT_LAYERSPEC_MSG(p_ccb->p_curr_msg->layer_specific); + sig = (UINT8) p_ccb->p_curr_msg->event; + AVDT_TRACE_DEBUG("avdt_msg_send label:%d, msg:%d, sig:%d\n", label, msg, sig); + + /* keep track of how much of msg we've sent */ + curr_msg_len -= p_buf->len; + if (curr_msg_len == 0) { + /* entire message sent; mark as finished */ + p_ccb->p_curr_msg = NULL; + + /* start timer here for commands */ + if (msg == AVDT_MSG_TYPE_CMD) { + /* if retransmit timeout set to zero, sig doesn't use retransmit */ + if ((sig == AVDT_SIG_DISCOVER) || (sig == AVDT_SIG_GETCAP) || + (sig == AVDT_SIG_SECURITY) || (avdt_cb.rcb.ret_tout == 0)) { + btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RSP, avdt_cb.rcb.sig_tout); + } else if (sig != AVDT_SIG_DELAY_RPT) { + btu_start_timer(&p_ccb->timer_entry, BTU_TTYPE_AVDT_CCB_RET, avdt_cb.rcb.ret_tout); + } + } + } else { + /* message being fragmented and not completely sent */ + p_ccb->p_curr_msg->len -= p_buf->len; + p_ccb->p_curr_msg->offset += p_buf->len; + } + + /* set up to build header */ + p_buf->len += hdr_len; + p_buf->offset -= hdr_len; + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* build header */ + AVDT_MSG_BLD_HDR(p, label, pkt_type, msg); + if (pkt_type == AVDT_PKT_TYPE_START) { + AVDT_MSG_BLD_NOSP(p, nosp); + } + if ((pkt_type == AVDT_PKT_TYPE_START) || (pkt_type == AVDT_PKT_TYPE_SINGLE)) { + AVDT_MSG_BLD_SIG(p, sig); + } + + /* send msg buffer down */ + avdt_ad_write_req(AVDT_CHAN_SIG, p_ccb, NULL, p_buf); + } + return (p_ccb->cong); +} + +/******************************************************************************* +** +** Function avdt_msg_asmbl +** +** Description Reassemble incoming message. +** +** +** Returns Pointer to reassembled message; NULL if no message +** available. +** +*******************************************************************************/ +BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf) +{ + UINT8 *p; + UINT8 pkt_type; + BT_HDR *p_ret; + UINT16 buf_len; + + /* parse the message header */ + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + AVDT_MSG_PRS_PKT_TYPE(p, pkt_type); + + /* quick sanity check on length */ + if (p_buf->len < avdt_msg_pkt_type_len[pkt_type]) { + GKI_freebuf(p_buf); + AVDT_TRACE_WARNING("Bad length during reassembly"); + p_ret = NULL; + } + /* single packet */ + else if (pkt_type == AVDT_PKT_TYPE_SINGLE) { + /* if reassembly in progress drop message and process new single */ + if (p_ccb->p_rx_msg != NULL) { + GKI_freebuf(p_ccb->p_rx_msg); + p_ccb->p_rx_msg = NULL; + AVDT_TRACE_WARNING("Got single during reassembly"); + } + p_ret = p_buf; + } + /* start packet */ + else if (pkt_type == AVDT_PKT_TYPE_START) { + /* if reassembly in progress drop message and process new single */ + if (p_ccb->p_rx_msg != NULL) { + GKI_freebuf(p_ccb->p_rx_msg); + AVDT_TRACE_WARNING("Got start during reassembly"); + } + p_ccb->p_rx_msg = p_buf; + + /* copy first header byte over nosp */ + *(p + 1) = *p; + + /* set offset to point to where to copy next */ + p_ccb->p_rx_msg->offset += p_ccb->p_rx_msg->len; + + /* adjust length for packet header */ + p_ccb->p_rx_msg->len -= 1; + + p_ret = NULL; + } + /* continue or end */ + else { + /* if no reassembly in progress drop message */ + if (p_ccb->p_rx_msg == NULL) { + GKI_freebuf(p_buf); + AVDT_TRACE_WARNING("Pkt type=%d out of order\n", pkt_type); + p_ret = NULL; + } else { + /* get size of buffer holding assembled message */ + buf_len = GKI_get_buf_size(p_ccb->p_rx_msg) - sizeof(BT_HDR); + + /* adjust offset and len of fragment for header byte */ + p_buf->offset += AVDT_LEN_TYPE_CONT; + p_buf->len -= AVDT_LEN_TYPE_CONT; + + /* verify length */ + if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len) { + /* won't fit; free everything */ + GKI_freebuf(p_ccb->p_rx_msg); + p_ccb->p_rx_msg = NULL; + GKI_freebuf(p_buf); + p_ret = NULL; + } else { + /* copy contents of p_buf to p_rx_msg */ + memcpy((UINT8 *)(p_ccb->p_rx_msg + 1) + p_ccb->p_rx_msg->offset, + (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len); + + if (pkt_type == AVDT_PKT_TYPE_END) { + p_ccb->p_rx_msg->offset -= p_ccb->p_rx_msg->len; + p_ccb->p_rx_msg->len += p_buf->len; + p_ret = p_ccb->p_rx_msg; + p_ccb->p_rx_msg = NULL; + } else { + p_ccb->p_rx_msg->offset += p_buf->len; + p_ccb->p_rx_msg->len += p_buf->len; + p_ret = NULL; + } + GKI_freebuf(p_buf); + } + } + } + return p_ret; +} + +/******************************************************************************* +** +** Function avdt_msg_send_cmd +** +** Description This function is called to send a command message. The +** sig_id parameter indicates the message type, p_params +** points to the message parameters, if any. It gets a buffer +** from the AVDTP command pool, executes the message building +** function for this message type. It then queues the message +** in the command queue for this CCB. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT8 *p_start; + + /* get a buffer */ + p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID); + if (p_buf == NULL) { + AVDT_TRACE_ERROR("avdt_msg_send_cmd out of buffer!!"); + return; + } + + /* set up gki buf pointer and offset */ + p_buf->offset = AVDT_MSG_OFFSET; + p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* execute parameter building function to build message */ + (*avdt_msg_bld_cmd[sig_id - 1])(&p, p_params); + + /* set len */ + p_buf->len = (UINT16) (p - p_start); + + /* now store scb hdls, if any, in buf */ + if (p_scb != NULL) { + p = (UINT8 *)(p_buf + 1); + + /* for start and suspend, p_scb points to array of handles */ + if ((sig_id == AVDT_SIG_START) || (sig_id == AVDT_SIG_SUSPEND)) { + memcpy(p, (UINT8 *) p_scb, p_buf->len); + } + /* for all others, p_scb points to scb as usual */ + else { + *p = avdt_scb_to_hdl((tAVDT_SCB *) p_scb); + } + } + + /* stash sig, label, and message type in buf */ + p_buf->event = sig_id; + AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_CMD, p_ccb->label); + + /* increment label */ + p_ccb->label = (p_ccb->label + 1) % 16; + + /* queue message and trigger ccb to send it */ + GKI_enqueue(&p_ccb->cmd_q, p_buf); + avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); +} + + +/******************************************************************************* +** +** Function avdt_msg_send_rsp +** +** Description This function is called to send a response message. The +** sig_id parameter indicates the message type, p_params +** points to the message parameters, if any. It gets a buffer +** from the AVDTP command pool, executes the message building +** function for this message type. It then queues the message +** in the response queue for this CCB. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT8 *p_start; + + /* get a buffer */ + p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID); + if (p_buf == NULL) { + return; + } + + /* set up gki buf pointer and offset */ + p_buf->offset = AVDT_MSG_OFFSET; + p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* execute parameter building function to build message */ + (*avdt_msg_bld_rsp[sig_id - 1])(&p, p_params); + + /* set length */ + p_buf->len = (UINT16) (p - p_start); + + /* stash sig, label, and message type in buf */ + p_buf->event = sig_id; + AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_RSP, p_params->hdr.label); + + /* queue message and trigger ccb to send it */ + GKI_enqueue(&p_ccb->rsp_q, p_buf); + avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); +} + + +/******************************************************************************* +** +** Function avdt_msg_send_rej +** +** Description This function is called to send a reject message. The +** sig_id parameter indicates the message type. It gets +** a buffer from the AVDTP command pool and builds the +** message based on the message type and the error code. +** It then queues the message in the response queue for +** this CCB. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT8 *p_start; + + /* get a buffer */ + p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID); + if (p_buf == NULL) { + return; + } + + /* set up gki buf pointer and offset */ + p_buf->offset = AVDT_MSG_OFFSET; + p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* if sig id included, build into message */ + if (sig_id != AVDT_SIG_NONE) { + /* if this sig has a parameter, add the parameter */ + if ((sig_id == AVDT_SIG_SETCONFIG) || + (sig_id == AVDT_SIG_RECONFIG)) { + AVDT_MSG_BLD_PARAM(p, p_params->hdr.err_param); + } else if ((sig_id == AVDT_SIG_START) || + (sig_id == AVDT_SIG_SUSPEND)) { + AVDT_MSG_BLD_SEID(p, p_params->hdr.err_param); + } + + /* add the error code */ + AVDT_MSG_BLD_ERR(p, p_params->hdr.err_code); + } + AVDT_TRACE_DEBUG("avdt_msg_send_rej"); + + /* calculate length */ + p_buf->len = (UINT16) (p - p_start); + + /* stash sig, label, and message type in buf */ + p_buf->event = sig_id; + AVDT_BLD_LAYERSPEC(p_buf->layer_specific, AVDT_MSG_TYPE_REJ, p_params->hdr.label); + + /* queue message and trigger ccb to send it */ + GKI_enqueue(&p_ccb->rsp_q, p_buf); + avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); +} + +/******************************************************************************* +** +** Function avdt_msg_send_grej +** +** Description This function is called to send a general reject message. The +** sig_id parameter indicates the message type. It gets +** a buffer from the AVDTP command pool and builds the +** message based on the message type and the error code. +** It then queues the message in the response queue for +** this CCB. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params) +{ + BT_HDR *p_buf; + UINT8 *p; + UINT8 *p_start; + + /* get a buffer */ + p_buf = (BT_HDR *) GKI_getpoolbuf(AVDT_CMD_POOL_ID); + if (p_buf == NULL) { + return; + } + + /* set up gki buf pointer and offset */ + p_buf->offset = AVDT_MSG_OFFSET; + p_start = p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* calculate length */ + p_buf->len = (UINT16) (p - p_start); + + /* stash sig, label, and message type in buf */ + p_buf->event = 0; + AVDT_BLD_LAYERSPEC(p_buf->layer_specific, 0, p_params->hdr.label); + AVDT_TRACE_DEBUG("avdt_msg_send_grej"); + + /* queue message and trigger ccb to send it */ + GKI_enqueue(&p_ccb->rsp_q, p_buf); + avdt_ccb_event(p_ccb, AVDT_CCB_SENDMSG_EVT, NULL); +} + +/******************************************************************************* +** +** Function avdt_msg_ind +** +** Description This function is called by the adaption layer when an +** incoming message is received on the signaling channel. +** It parses the message and sends an event to the appropriate +** SCB or CCB for the message. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf) +{ + tAVDT_SCB *p_scb; + UINT8 *p; + BOOLEAN ok = TRUE; + BOOLEAN handle_rsp = FALSE; + BOOLEAN gen_rej = FALSE; + UINT8 label; + UINT8 pkt_type; + UINT8 msg_type; + UINT8 sig = 0; + tAVDT_MSG msg; + tAVDT_CFG cfg; + UINT8 err; + UINT8 evt = 0; + UINT8 scb_hdl; + + /* reassemble message; if no message available (we received a fragment) return */ + if ((p_buf = avdt_msg_asmbl(p_ccb, p_buf)) == NULL) { + return; + } + + p = (UINT8 *)(p_buf + 1) + p_buf->offset; + + /* parse the message header */ + AVDT_MSG_PRS_HDR(p, label, pkt_type, msg_type); + + UNUSED(pkt_type); + + AVDT_TRACE_DEBUG("msg_type=%d, sig=%d\n", msg_type, sig); + /* set up label and ccb_idx in message hdr */ + msg.hdr.label = label; + msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); + + /* verify msg type */ + if (msg_type == AVDT_MSG_TYPE_GRJ) { + AVDT_TRACE_WARNING("Dropping msg msg_type=%d\n", msg_type); + ok = FALSE; + } + /* check for general reject */ + else if ((msg_type == AVDT_MSG_TYPE_REJ) && (p_buf->len == AVDT_LEN_GEN_REJ)) { + gen_rej = TRUE; + if (p_ccb->p_curr_cmd != NULL) { + msg.hdr.sig_id = sig = (UINT8) p_ccb->p_curr_cmd->event; + evt = avdt_msg_rej_2_evt[sig - 1]; + msg.hdr.err_code = AVDT_ERR_NSC; + msg.hdr.err_param = 0; + } + } else { /* not a general reject */ + /* get and verify signal */ + AVDT_MSG_PRS_SIG(p, sig); + msg.hdr.sig_id = sig; + if ((sig == 0) || (sig > AVDT_SIG_MAX)) { + AVDT_TRACE_WARNING("Dropping msg sig=%d msg_type:%d\n", sig, msg_type); + ok = FALSE; + + /* send a general reject */ + if (msg_type == AVDT_MSG_TYPE_CMD) { + avdt_msg_send_grej(p_ccb, sig, &msg); + } + } + } + + if (ok && !gen_rej) { + /* skip over header (msg length already verified during reassembly) */ + p_buf->len -= AVDT_LEN_TYPE_SINGLE; + + /* set up to parse message */ + if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_DISCOVER)) { + /* parse discover rsp message to struct supplied by app */ + msg.discover_rsp.p_sep_info = (tAVDT_SEP_INFO *) p_ccb->p_proc_data; + msg.discover_rsp.num_seps = p_ccb->proc_param; + } else if ((msg_type == AVDT_MSG_TYPE_RSP) && + ((sig == AVDT_SIG_GETCAP) || (sig == AVDT_SIG_GET_ALLCAP))) { + /* parse discover rsp message to struct supplied by app */ + msg.svccap.p_cfg = (tAVDT_CFG *) p_ccb->p_proc_data; + } else if ((msg_type == AVDT_MSG_TYPE_RSP) && (sig == AVDT_SIG_GETCONFIG)) { + /* parse get config rsp message to struct allocated locally */ + msg.svccap.p_cfg = &cfg; + } else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_SETCONFIG)) { + /* parse config cmd message to struct allocated locally */ + msg.config_cmd.p_cfg = &cfg; + } else if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig == AVDT_SIG_RECONFIG)) { + /* parse reconfig cmd message to struct allocated locally */ + msg.reconfig_cmd.p_cfg = &cfg; + } + + /* parse message; while we're at it map message sig to event */ + if (msg_type == AVDT_MSG_TYPE_CMD) { + msg.hdr.err_code = err = (*avdt_msg_prs_cmd[sig - 1])(&msg, p, p_buf->len); + evt = avdt_msg_cmd_2_evt[sig - 1]; + } else if (msg_type == AVDT_MSG_TYPE_RSP) { + msg.hdr.err_code = err = (*avdt_msg_prs_rsp[sig - 1])(&msg, p, p_buf->len); + evt = avdt_msg_rsp_2_evt[sig - 1]; + } else { /* msg_type == AVDT_MSG_TYPE_REJ */ + err = avdt_msg_prs_rej(&msg, p, sig); + evt = avdt_msg_rej_2_evt[sig - 1]; + } + + /* if parsing failed */ + if (err != 0) { + AVDT_TRACE_WARNING("Parsing failed sig=%d err=0x%x\n", sig, err); + + /* if its a rsp or rej, drop it; if its a cmd, send a rej; + ** note special case for abort; never send abort reject + */ + ok = FALSE; + if ((msg_type == AVDT_MSG_TYPE_CMD) && (sig != AVDT_SIG_ABORT)) { + avdt_msg_send_rej(p_ccb, sig, &msg); + } + } + } + + /* if its a rsp or rej, check sent cmd to see if we're waiting for + ** the rsp or rej. If we didn't send a cmd for it, drop it. If + ** it does match a cmd, stop timer for the cmd. + */ + if (ok) { + if ((msg_type == AVDT_MSG_TYPE_RSP) || (msg_type == AVDT_MSG_TYPE_REJ)) { + if ((p_ccb->p_curr_cmd != NULL) && + (p_ccb->p_curr_cmd->event == sig) && + (AVDT_LAYERSPEC_LABEL(p_ccb->p_curr_cmd->layer_specific) == label)) { + /* stop timer */ + btu_stop_timer(&p_ccb->timer_entry); + + /* clear retransmission count */ + p_ccb->ret_count = 0; + + /* later in this function handle ccb event */ + handle_rsp = TRUE; + } else { + ok = FALSE; + AVDT_TRACE_WARNING("Cmd not found for rsp sig=%d label=%d\n", sig, label); + } + } + } + + if (ok) { + /* if it's a ccb event send to ccb */ + if (evt & AVDT_CCB_MKR) { + avdt_ccb_event(p_ccb, (UINT8)(evt & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &msg); + } + /* if it's a scb event */ + else { + /* Scb events always have a single seid. For cmd, get seid from + ** message. For rej and rsp, get seid from p_curr_cmd. + */ + if (msg_type == AVDT_MSG_TYPE_CMD) { + scb_hdl = msg.single.seid; + } else { + scb_hdl = *((UINT8 *)(p_ccb->p_curr_cmd + 1)); + } + + /* Map seid to the scb and send it the event. For cmd, seid has + ** already been verified by parsing function. + */ + if (evt && (p_scb = avdt_scb_by_hdl(scb_hdl)) != NULL) { + avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT *) &msg); + } + } + } + + /* free message buffer */ + GKI_freebuf(p_buf); + + /* if its a rsp or rej, send event to ccb to free associated + ** cmd msg buffer and handle cmd queue + */ + if (handle_rsp) { + avdt_ccb_event(p_ccb, AVDT_CCB_RCVRSP_EVT, NULL); + } +} + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_scb.c b/components/bt/bluedroid/stack/avdt/avdt_scb.c new file mode 100644 index 0000000000..7f4dc7229c --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_scb.c @@ -0,0 +1,789 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains the stream control block and functions which + * operate on the stream control block. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "gki.h" +#include "btu.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) + +/***************************************************************************** +** state machine constants and types +*****************************************************************************/ +#if AVDT_DEBUG == TRUE + +/* verbose state strings for trace */ +const char *const avdt_scb_st_str[] = { + "SCB_IDLE_ST", + "SCB_CONF_ST", + "SCB_OPENING_ST", + "SCB_OPEN_ST", + "SCB_STREAM_ST", + "SCB_CLOSING_ST" +}; + +/* verbose event strings for trace */ +const char *const avdt_scb_evt_str[] = { + "API_REMOVE_EVT", + "API_WRITE_REQ_EVT", + "API_GETCONFIG_REQ_EVT", + "API_DELAY_RPT_REQ", + "API_SETCONFIG_REQ_EVT", + "API_OPEN_REQ_EVT", + "API_CLOSE_REQ_EVT", + "API_RECONFIG_REQ_EVT", + "API_SECURITY_REQ_EVT", + "API_ABORT_REQ_EVT", + "API_GETCONFIG_RSP_EVT", + "API_SETCONFIG_RSP_EVT", + "API_SETCONFIG_REJ_EVT", + "API_OPEN_RSP_EVT", + "API_CLOSE_RSP_EVT", + "API_RECONFIG_RSP_EVT", + "API_SECURITY_RSP_EVT", + "API_ABORT_RSP_EVT", + "MSG_SETCONFIG_CMD_EVT", + "MSG_GETCONFIG_CMD_EVT", + "MSG_OPEN_CMD_EVT", + "MSG_START_CMD_EVT", + "MSG_SUSPEND_CMD_EVT", + "MSG_CLOSE_CMD_EVT", + "MSG_ABORT_CMD_EVT", + "MSG_RECONFIG_CMD_EVT", + "MSG_SECURITY_CMD_EVT", + "MSG_DELAY_RPT_CMD_EVT", + "MSG_DELAY_RPT_RSP_EVT", + "MSG_SETCONFIG_RSP_EVT", + "MSG_GETCONFIG_RSP_EVT", + "MSG_OPEN_RSP_EVT", + "MSG_START_RSP_EVT", + "MSG_SUSPEND_RSP_EVT", + "MSG_CLOSE_RSP_EVT", + "MSG_ABORT_RSP_EVT", + "MSG_RECONFIG_RSP_EVT", + "MSG_SECURITY_RSP_EVT", + "MSG_SETCONFIG_REJ_EVT", + "MSG_OPEN_REJ_EVT", + "MSG_START_REJ_EVT", + "MSG_SUSPEND_REJ_EVT", + "TC_TOUT_EVT", + "TC_OPEN_EVT", + "TC_CLOSE_EVT", + "TC_CONG_EVT", + "TC_DATA_EVT", + "CC_CLOSE_EVT" +}; + +#endif + + +/* action function list */ +const tAVDT_SCB_ACTION avdt_scb_action[] = { + avdt_scb_hdl_abort_cmd, + avdt_scb_hdl_abort_rsp, + avdt_scb_hdl_close_cmd, + avdt_scb_hdl_close_rsp, + avdt_scb_hdl_getconfig_cmd, + avdt_scb_hdl_getconfig_rsp, + avdt_scb_hdl_open_cmd, + avdt_scb_hdl_open_rej, + avdt_scb_hdl_open_rsp, + avdt_scb_hdl_pkt, + avdt_scb_drop_pkt, + avdt_scb_hdl_reconfig_cmd, + avdt_scb_hdl_reconfig_rsp, + avdt_scb_hdl_security_cmd, + avdt_scb_hdl_security_rsp, + avdt_scb_hdl_setconfig_cmd, + avdt_scb_hdl_setconfig_rej, + avdt_scb_hdl_setconfig_rsp, + avdt_scb_hdl_start_cmd, + avdt_scb_hdl_start_rsp, + avdt_scb_hdl_suspend_cmd, + avdt_scb_hdl_suspend_rsp, + avdt_scb_hdl_tc_close, +#if AVDT_REPORTING == TRUE + avdt_scb_hdl_tc_close_sto, +#endif + avdt_scb_hdl_tc_open, +#if AVDT_REPORTING == TRUE + avdt_scb_hdl_tc_open_sto, +#endif + avdt_scb_snd_delay_rpt_req, + avdt_scb_hdl_delay_rpt_cmd, + avdt_scb_hdl_delay_rpt_rsp, + avdt_scb_hdl_write_req, + avdt_scb_snd_abort_req, + avdt_scb_snd_abort_rsp, + avdt_scb_snd_close_req, + avdt_scb_snd_stream_close, + avdt_scb_snd_close_rsp, + avdt_scb_snd_getconfig_req, + avdt_scb_snd_getconfig_rsp, + avdt_scb_snd_open_req, + avdt_scb_snd_open_rsp, + avdt_scb_snd_reconfig_req, + avdt_scb_snd_reconfig_rsp, + avdt_scb_snd_security_req, + avdt_scb_snd_security_rsp, + avdt_scb_snd_setconfig_req, + avdt_scb_snd_setconfig_rej, + avdt_scb_snd_setconfig_rsp, + avdt_scb_snd_tc_close, + avdt_scb_cb_err, + avdt_scb_cong_state, + avdt_scb_rej_state, + avdt_scb_rej_in_use, + avdt_scb_rej_not_in_use, + avdt_scb_set_remove, + avdt_scb_free_pkt, + avdt_scb_clr_pkt, + avdt_scb_chk_snd_pkt, + avdt_scb_tc_timer, + avdt_scb_clr_vars, + avdt_scb_dealloc +}; + +/* state table information */ +#define AVDT_SCB_ACTIONS 2 /* number of actions */ +#define AVDT_SCB_NEXT_STATE 2 /* position of next state */ +#define AVDT_SCB_NUM_COLS 3 /* number of columns in state tables */ + +/* state table for idle state */ +const UINT8 avdt_scb_st_idle[][AVDT_SCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REMOVE_EVT */ {AVDT_SCB_DEALLOC, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_SND_SETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_SND_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_SND_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_SETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_NOT_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_SETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_HDL_SETCONFIG_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* CC_CLOSE_EVT */ {AVDT_SCB_CLR_VARS, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST} +}; + +/* state table for configured state */ +const UINT8 avdt_scb_st_conf[][AVDT_SCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REMOVE_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CONF_ST}, + /* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_OPEN_REQ_EVT */ {AVDT_SCB_SND_OPEN_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_OPEN_RSP_EVT */ {AVDT_SCB_SND_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST}, + /* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_IN_USE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_OPEN_CMD_EVT */ {AVDT_SCB_HDL_OPEN_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_OPEN_RSP_EVT */ {AVDT_SCB_HDL_OPEN_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_ABORT_RSP_EVT */ {AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IDLE_ST}, + /* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_OPEN_REJ_EVT */ {AVDT_SCB_HDL_OPEN_REJ, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* TC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CONF_ST}, + /* CC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST} +}; + +/* state table for opening state */ +const UINT8 avdt_scb_st_opening[][AVDT_SCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST}, + /* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_CLOSING_ST}, + /* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST}, + /* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* TC_TOUT_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPENING_ST}, + /* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST} +}; + +/* state table for open state */ +const UINT8 avdt_scb_st_open[][AVDT_SCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REMOVE_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST}, + /* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_CLOSE_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_REQ_EVT */ {AVDT_SCB_SND_RECONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_RSP_EVT */ {AVDT_SCB_SND_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST}, + /* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_START_CMD_EVT */ {AVDT_SCB_HDL_START_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_HDL_RECONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_START_RSP_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, +#if AVDT_REPORTING == TRUE + /* TC_OPEN_EVT */ {AVDT_SCB_HDL_TC_OPEN_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE_STO, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, +#else + /* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, +#endif + /* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_OPEN_ST}, + /* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST} +}; + +/* state table for streaming state */ +const UINT8 avdt_scb_st_stream[][AVDT_SCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REMOVE_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_SET_REMOVE, AVDT_SCB_CLOSING_ST}, + /* API_WRITE_REQ_EVT */ {AVDT_SCB_HDL_WRITE_REQ, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST}, + /* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_SND_GETCONFIG_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_SND_DELAY_RPT_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_OPEN_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_CLOSE_REQ_EVT */ {AVDT_SCB_SND_STREAM_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_SECURITY_REQ_EVT */ {AVDT_SCB_SND_SECURITY_REQ, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_ABORT_REQ_EVT */ {AVDT_SCB_SND_ABORT_REQ, AVDT_SCB_CLR_PKT, AVDT_SCB_CLOSING_ST}, + /* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_SND_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_CLOSE_RSP_EVT */ {AVDT_SCB_SND_CLOSE_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_SECURITY_RSP_EVT */ {AVDT_SCB_SND_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_TC_TIMER, AVDT_SCB_CLOSING_ST}, + /* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_HDL_GETCONFIG_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_HDL_SUSPEND_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST}, + /* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_HDL_CLOSE_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_CLR_PKT, AVDT_SCB_STREAM_ST}, + /* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_HDL_SECURITY_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_HDL_DELAY_RPT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_HDL_GETCONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_CLR_PKT, AVDT_SCB_OPEN_ST}, + /* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_ABORT_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_HDL_RECONFIG_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_HDL_SECURITY_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* TC_TOUT_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* TC_OPEN_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_CONG_EVT */ {AVDT_SCB_CONG_STATE, AVDT_SCB_CHK_SND_PKT, AVDT_SCB_STREAM_ST}, + /* TC_DATA_EVT */ {AVDT_SCB_HDL_PKT, AVDT_SCB_IGNORE, AVDT_SCB_STREAM_ST}, + /* CC_CLOSE_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST} +}; + +/* state table for closing state */ +const UINT8 avdt_scb_st_closing[][AVDT_SCB_NUM_COLS] = { + /* Event Action 1 Action 2 Next state */ + /* API_REMOVE_EVT */ {AVDT_SCB_SET_REMOVE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_WRITE_REQ_EVT */ {AVDT_SCB_FREE_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_GETCONFIG_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_DELAY_RPT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_SETCONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_OPEN_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_CLOSE_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_SECURITY_REQ_EVT */ {AVDT_SCB_CB_ERR, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_ABORT_REQ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_CLOSE_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* API_ABORT_RSP_EVT */ {AVDT_SCB_SND_ABORT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_GETCONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_OPEN_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_START_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SUSPEND_CMD_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_CLOSE_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_ABORT_CMD_EVT */ {AVDT_SCB_HDL_ABORT_CMD, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_RECONFIG_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SECURITY_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_DELAY_RPT_CMD_EVT */ {AVDT_SCB_REJ_STATE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_DELAY_RPT_RSP_EVT */ {AVDT_SCB_HDL_DELAY_RPT_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_GETCONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_OPEN_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_START_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SUSPEND_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_CLOSE_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_CLOSE_RSP, AVDT_SCB_CLOSING_ST}, + /* MSG_ABORT_RSP_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_HDL_ABORT_RSP, AVDT_SCB_CLOSING_ST}, + /* MSG_RECONFIG_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SECURITY_RSP_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SETCONFIG_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_OPEN_REJ_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_START_REJ_EVT */ {AVDT_SCB_HDL_START_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* MSG_SUSPEND_REJ_EVT */ {AVDT_SCB_HDL_SUSPEND_RSP, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* TC_TOUT_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* TC_OPEN_EVT */ {AVDT_SCB_SND_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* TC_CLOSE_EVT */ {AVDT_SCB_HDL_TC_CLOSE, AVDT_SCB_IGNORE, AVDT_SCB_IDLE_ST}, + /* TC_CONG_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* TC_DATA_EVT */ {AVDT_SCB_DROP_PKT, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST}, + /* CC_CLOSE_EVT */ {AVDT_SCB_IGNORE, AVDT_SCB_IGNORE, AVDT_SCB_CLOSING_ST} +}; + +/* type for state table */ +typedef const UINT8 (*tAVDT_SCB_ST_TBL)[AVDT_SCB_NUM_COLS]; + +/* state table */ +const tAVDT_SCB_ST_TBL avdt_scb_st_tbl[] = { + avdt_scb_st_idle, + avdt_scb_st_conf, + avdt_scb_st_opening, + avdt_scb_st_open, + avdt_scb_st_stream, + avdt_scb_st_closing +}; + + +/******************************************************************************* +** +** Function avdt_scb_event +** +** Description State machine event handling function for scb +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data) +{ + tAVDT_SCB_ST_TBL state_table; + UINT8 action; + int i; + +#if AVDT_DEBUG == TRUE + AVDT_TRACE_EVENT("SCB hdl=%d event=%d/%s state=%s\n", avdt_scb_to_hdl(p_scb), event, avdt_scb_evt_str[event], avdt_scb_st_str[p_scb->state]); +#endif + /* set current event */ + p_scb->curr_evt = event; + + /* look up the state table for the current state */ + state_table = avdt_scb_st_tbl[p_scb->state]; + + /* set next state */ + if (p_scb->state != state_table[event][AVDT_SCB_NEXT_STATE]) { + p_scb->state = state_table[event][AVDT_SCB_NEXT_STATE]; + } + + /* execute action functions */ + for (i = 0; i < AVDT_SCB_ACTIONS; i++) { + if ((action = state_table[event][i]) != AVDT_SCB_IGNORE) { + (*avdt_cb.p_scb_act[action])(p_scb, p_data); + } else { + break; + } + } +} + + +/******************************************************************************* +** +** Function avdt_scb_init +** +** Description Initialize stream control block module. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_init(void) +{ + memset(&avdt_cb.scb[0], 0, sizeof(tAVDT_SCB) * AVDT_NUM_SEPS); + avdt_cb.p_scb_act = (tAVDT_SCB_ACTION *) avdt_scb_action; +} + + +/******************************************************************************* +** +** Function avdt_scb_alloc +** +** Description Allocate a stream control block. +** +** +** Returns pointer to the scb, or NULL if none could be allocated. +** +*******************************************************************************/ +tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs) +{ + tAVDT_SCB *p_scb = &avdt_cb.scb[0]; + int i; + + /* find available scb */ + for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { + if (!p_scb->allocated) { + memset(p_scb, 0, sizeof(tAVDT_SCB)); + p_scb->allocated = TRUE; + p_scb->p_ccb = NULL; + + /* initialize sink as activated */ + if (p_cs->tsep == AVDT_TSEP_SNK) { + p_scb->sink_activated = TRUE; + } + + memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS)); +#if AVDT_MULTIPLEXING == TRUE + /* initialize fragments gueue */ + GKI_init_q(&p_scb->frag_q); + + if (p_cs->cfg.psc_mask & AVDT_PSC_MUX) { + p_scb->cs.cfg.mux_tcid_media = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb); +#if AVDT_REPORTING == TRUE + if (p_cs->cfg.psc_mask & AVDT_PSC_REPORT) { + p_scb->cs.cfg.mux_tcid_report = avdt_ad_type_to_tcid(AVDT_CHAN_REPORT, p_scb); + } +#endif + } +#endif + p_scb->timer_entry.param = (UINT32) p_scb; + AVDT_TRACE_DEBUG("avdt_scb_alloc hdl=%d, psc_mask:0x%x\n", i + 1, p_cs->cfg.psc_mask); + break; + } + } + + if (i == AVDT_NUM_SEPS) { + /* out of ccbs */ + p_scb = NULL; + AVDT_TRACE_WARNING("Out of scbs"); + } + + return p_scb; +} + +/******************************************************************************* +** +** Function avdt_scb_dealloc +** +** Description Deallocate a stream control block. +** +** +** Returns void. +** +*******************************************************************************/ +void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ +#if AVDT_MULTIPLEXING == TRUE + void *p_buf; +#endif + UNUSED(p_data); + + AVDT_TRACE_DEBUG("avdt_scb_dealloc hdl=%d\n", avdt_scb_to_hdl(p_scb)); + btu_stop_timer(&p_scb->timer_entry); + +#if AVDT_MULTIPLEXING == TRUE + /* free fragments we're holding, if any; it shouldn't happen */ + while ((p_buf = GKI_dequeue (&p_scb->frag_q)) != NULL) { + GKI_freebuf(p_buf); + } +#endif + + memset(p_scb, 0, sizeof(tAVDT_SCB)); +} + +/******************************************************************************* +** +** Function avdt_scb_to_hdl +** +** Description Given a pointer to an scb, return its handle (or seid). +** +** +** Returns Index of scb. +** +*******************************************************************************/ +UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb) +{ + return (UINT8) (p_scb - avdt_cb.scb + 1); +} + +/******************************************************************************* +** +** Function avdt_scb_by_hdl +** +** Description Given an scb handle (or seid), return a pointer to the scb. +** +** +** Returns Pointer to scb or NULL if index is out of range or scb +** is not allocated. +** +*******************************************************************************/ +tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl) +{ + tAVDT_SCB *p_scb; + + /* verify index */ + if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS)) { + p_scb = &avdt_cb.scb[hdl - 1]; + + /* verify scb is allocated */ + if (!p_scb->allocated) { + p_scb = NULL; + AVDT_TRACE_WARNING("scb hdl %d not allocated\n", hdl); + } + } else { + p_scb = NULL; + AVDT_TRACE_WARNING("scb hdl %d out of range\n", hdl); + } + return p_scb; +} + +/******************************************************************************* +** +** Function avdt_scb_verify +** +** Description Verify the condition of a list of scbs. +** +** +** Returns SEID that failed, or 0 if success. +** +*******************************************************************************/ +UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code) +{ + int i; + tAVDT_SCB *p_scb; + UINT8 nsc_mask; + UINT8 ret = 0; + + AVDT_TRACE_DEBUG("avdt_scb_verify state %d\n", state); + /* set nonsupported command mask */ + /* translate public state into private state */ + nsc_mask = 0; + if (state == AVDT_VERIFY_SUSPEND) { + nsc_mask = AVDT_NSC_SUSPEND; + } + + /* verify every scb */ + for (i = 0, *p_err_code = 0; (i < num_seid) && (*p_err_code == 0) && (i < AVDT_NUM_SEPS); i++) { + if ((p_scb = avdt_scb_by_hdl(p_seid[i])) == NULL) { + *p_err_code = AVDT_ERR_BAD_STATE; + } else if (p_scb->p_ccb != p_ccb) { + *p_err_code = AVDT_ERR_BAD_STATE; + } else if (p_scb->cs.nsc_mask & nsc_mask) { + *p_err_code = AVDT_ERR_NSC; + } + + switch (state) { + case AVDT_VERIFY_OPEN: + case AVDT_VERIFY_START: + if (p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST) { + *p_err_code = AVDT_ERR_BAD_STATE; + } + break; + + case AVDT_VERIFY_SUSPEND: + case AVDT_VERIFY_STREAMING: + if (p_scb->state != AVDT_SCB_STREAM_ST) { + *p_err_code = AVDT_ERR_BAD_STATE; + } + break; + } + } + + if ((i != num_seid) && (i < AVDT_NUM_SEPS)) { + ret = p_seid[i]; + } + + return ret; +} + +/******************************************************************************* +** +** Function avdt_scb_peer_seid_list +** +** Description Given a list of SCB handles, return a list of peer SEIDs +** for the handles, copied in place into the struct passed in. +** +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi) +{ + int i; + tAVDT_SCB *p_scb; + + for (i = 0; i < p_multi->num_seps; i++) { + if ((p_scb = avdt_scb_by_hdl(p_multi->seid_list[i])) != NULL) { + p_multi->seid_list[i] = p_scb->peer_seid; + } + } +} + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/stack/avdt/avdt_scb_act.c b/components/bt/bluedroid/stack/avdt/avdt_scb_act.c new file mode 100644 index 0000000000..ec270d2689 --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/avdt_scb_act.c @@ -0,0 +1,2087 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This module contains the action functions associated with the stream + * control block state machine. + * + ******************************************************************************/ + +#include +#include "bt_types.h" +#include "bt_target.h" +#include "bt_utils.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_int.h" +#include "gki.h" +#include "btu.h" + +#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) + +/* This table is used to lookup the callback event that matches a particular +** state machine API request event. Note that state machine API request +** events are at the beginning of the event list starting at zero, thus +** allowing for this table. +*/ +const UINT8 avdt_scb_cback_evt[] = { + 0, /* API_REMOVE_EVT (no event) */ + AVDT_WRITE_CFM_EVT, /* API_WRITE_REQ_EVT */ + 0, /* API_GETCONFIG_REQ_EVT (no event) */ + 0, /* API_DELAY_RPT_REQ_EVT (no event) */ + AVDT_OPEN_CFM_EVT, /* API_SETCONFIG_REQ_EVT */ + AVDT_OPEN_CFM_EVT, /* API_OPEN_REQ_EVT */ + AVDT_CLOSE_CFM_EVT, /* API_CLOSE_REQ_EVT */ + AVDT_RECONFIG_CFM_EVT, /* API_RECONFIG_REQ_EVT */ + AVDT_SECURITY_CFM_EVT, /* API_SECURITY_REQ_EVT */ + 0 /* API_ABORT_REQ_EVT (no event) */ +}; + +/* This table is used to look up the callback event based on the signaling +** role when the stream is closed. +*/ +const UINT8 avdt_scb_role_evt[] = { + AVDT_CLOSE_IND_EVT, /* AVDT_CLOSE_ACP */ + AVDT_CLOSE_CFM_EVT, /* AVDT_CLOSE_INT */ + AVDT_CLOSE_IND_EVT, /* AVDT_OPEN_ACP */ + AVDT_OPEN_CFM_EVT /* AVDT_OPEN_INT */ +}; + +/******************************************************************************* +** +** Function avdt_scb_gen_ssrc +** +** Description This function generates a SSRC number unique to the stream. +** +** Returns SSRC value. +** +*******************************************************************************/ +UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb) +{ + /* combine the value of the media type and codec type of the SCB */ + return ((UINT32)(p_scb->cs.cfg.codec_info[1] | p_scb->cs.cfg.codec_info[2])); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_abort_cmd +** +** Description This function sends the SCB an AVDT_SCB_API_ABORT_RSP_EVT +** to initiate sending of an abort response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + p_scb->role = AVDT_CLOSE_ACP; + avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_RSP_EVT, p_data); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_abort_rsp +** +** Description This function is an empty function; it serves as a +** placeholder for a conformance API action function. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_scb); + UNUSED(p_data); + return; +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_close_cmd +** +** Description This function sends the SCB an AVDT_SCB_API_CLOSE_RSP_EVT +** to initiate sending of a close response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + p_scb->role = AVDT_CLOSE_ACP; + avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_RSP_EVT, p_data); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_close_rsp +** +** Description This function sets the close_code variable to the error +** code returned in the close response. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + p_scb->close_code = p_data->msg.hdr.err_code; +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_getconfig_cmd +** +** Description This function retrieves the configuration parameters of +** the SCB and sends the SCB an AVDT_SCB_API_GETCONFIG_RSP_EVT +** to initiate sending of a get configuration response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + p_data->msg.svccap.p_cfg = &p_scb->curr_cfg; + + avdt_scb_event(p_scb, AVDT_SCB_API_GETCONFIG_RSP_EVT, p_data); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_getconfig_rsp +** +** Description This function is an empty function; it serves as a +** placeholder for a conformance API action function. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_scb); + UNUSED(p_data); + return; +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_open_cmd +** +** Description This function sends the SCB an AVDT_SCB_API_OPEN_RSP_EVT +** to initiate sending of an open response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_RSP_EVT, p_data); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_open_rej +** +** Description This function calls the application callback function +** indicating the open request has failed. It initializes +** certain SCB variables and sends a AVDT_CCB_UL_CLOSE_EVT +** to the CCB. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + /* do exactly same as setconfig reject */ + avdt_scb_hdl_setconfig_rej(p_scb, p_data); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_open_rsp +** +** Description This function calls avdt_ad_open_req() to initiate +** connection of the transport channel for this stream. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_data); + + /* initiate opening of trans channels for this SEID */ + p_scb->role = AVDT_OPEN_INT; + avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_INT); + + /* start tc connect timer */ + btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_pkt_no_frag +** +** Description +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UINT8 *p, *p_start; + UINT8 o_v, o_p, o_x, o_cc; + UINT8 m_pt; + UINT8 marker; + UINT16 seq; + UINT32 time_stamp; + UINT16 offset; + UINT16 ex_len; + UINT8 pad_len = 0; + + p = p_start = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset; + + /* parse media packet header */ + AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc); + AVDT_MSG_PRS_M_PT(p, m_pt, marker); + BE_STREAM_TO_UINT16(seq, p); + BE_STREAM_TO_UINT32(time_stamp, p); + p += 4; + + UNUSED(o_v); + + /* skip over any csrc's in packet */ + p += o_cc * 4; + + /* check for and skip over extension header */ + if (o_x) { + p += 2; + BE_STREAM_TO_UINT16(ex_len, p); + p += ex_len * 4; + } + + /* save our new offset */ + offset = (UINT16) (p - p_start); + + /* adjust length for any padding at end of packet */ + if (o_p) { + /* padding length in last byte of packet */ + pad_len = *(p_start + p_data->p_pkt->len); + } + + /* do sanity check */ + if ((offset > p_data->p_pkt->len) || ((pad_len + offset) > p_data->p_pkt->len)) { + AVDT_TRACE_WARNING("Got bad media packet"); + GKI_freebuf(p_data->p_pkt); + } + /* adjust offset and length and send it up */ + else { + p_data->p_pkt->len -= (offset + pad_len); + p_data->p_pkt->offset += offset; + + if (p_scb->cs.p_data_cback != NULL) { + /* report sequence number */ + p_data->p_pkt->layer_specific = seq; + (*p_scb->cs.p_data_cback)(avdt_scb_to_hdl(p_scb), p_data->p_pkt, + time_stamp, (UINT8)(m_pt | (marker << 7))); + } else { +#if AVDT_MULTIPLEXING == TRUE + if ((p_scb->cs.p_media_cback != NULL) + && (p_scb->p_media_buf != NULL) + && (p_scb->media_buf_len > p_data->p_pkt->len)) { + /* media buffer enough length is assigned by application. Lets use it*/ + memcpy(p_scb->p_media_buf, (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset, + p_data->p_pkt->len); + (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb), p_scb->p_media_buf, + p_scb->media_buf_len, time_stamp, seq, m_pt, marker); + } +#endif + GKI_freebuf(p_data->p_pkt); + } + } +} + +#if AVDT_REPORTING == TRUE +/******************************************************************************* +** +** Function avdt_scb_hdl_report +** +** Description +** +** Returns Nothing. +** +*******************************************************************************/ +UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) +{ + UINT16 result = AVDT_SUCCESS; + UINT8 *p_start = p; + UINT32 ssrc; + UINT8 o_v, o_p, o_cc; + AVDT_REPORT_TYPE pt; + tAVDT_REPORT_DATA report, *p_rpt; + + AVDT_TRACE_DEBUG( "avdt_scb_hdl_report"); + if (p_scb->cs.p_report_cback) { + p_rpt = &report; + /* parse report packet header */ + AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc); + pt = *p++; + p += 2; + BE_STREAM_TO_UINT32(ssrc, p); + + UNUSED(o_p); + UNUSED(o_v); + + switch (pt) { + case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */ + BE_STREAM_TO_UINT32(report.sr.ntp_sec, p); + BE_STREAM_TO_UINT32(report.sr.ntp_frac, p); + BE_STREAM_TO_UINT32(report.sr.rtp_time, p); + BE_STREAM_TO_UINT32(report.sr.pkt_count, p); + BE_STREAM_TO_UINT32(report.sr.octet_count, p); + break; + + case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */ + report.rr.frag_lost = *p; + BE_STREAM_TO_UINT32(report.rr.packet_lost, p); + report.rr.packet_lost &= 0xFFFFFF; + BE_STREAM_TO_UINT32(report.rr.seq_num_rcvd, p); + BE_STREAM_TO_UINT32(report.rr.jitter, p); + BE_STREAM_TO_UINT32(report.rr.lsr, p); + BE_STREAM_TO_UINT32(report.rr.dlsr, p); + break; + + case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */ + if (*p == AVDT_RTCP_SDES_CNAME) { + p_rpt = (tAVDT_REPORT_DATA *)(p + 2); + } else { + AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d %s\n", + ssrc, o_cc, *p, *(p + 1), p + 2); + result = AVDT_BUSY; + } + break; + + default: + AVDT_TRACE_ERROR( "Bad Report pkt - packet type: %d\n", pt); + result = AVDT_BAD_PARAMS; + } + + if (result == AVDT_SUCCESS) { + (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt); + } + + } + p_start += len; + return p_start; +} +#endif + +#if AVDT_MULTIPLEXING == TRUE +/******************************************************************************* +** +** Function avdt_scb_hdl_pkt_frag +** +** Description +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_pkt_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + /* Fields of Adaptation Layer Header */ + UINT8 al_tsid, al_frag, al_lcode; + UINT16 al_len; + /* media header fields */ + UINT8 o_v, o_p, o_x, o_cc; + UINT8 m_pt; + UINT8 marker; + UINT16 seq; + UINT32 time_stamp; + UINT32 ssrc; + UINT16 ex_len; + UINT8 pad_len; + /* other variables */ + UINT8 *p; /* current pointer */ + UINT8 *p_end; /* end of all packet */ + UINT8 *p_payload; /* pointer to media fragment payload in the buffer */ + UINT32 payload_len; /* payload length */ + UINT16 frag_len; /* fragment length */ + + p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset; + p_end = p + p_data->p_pkt->len; + /* parse all fragments */ + while (p < p_end) { + if (p_end - p < 4) { /* length check. maximum length of AL header = 4 */ + AVDT_TRACE_WARNING("p_end: %p - p:%p < 4\n", p_end, p); + break; + } + + /* parse first byte */ + al_tsid = (*p) >> 3; + al_frag = ( (*p) >> 2 ) & 0x01; + al_lcode = (*p++) & AVDT_ALH_LCODE_MASK; + + /* in case of TSID=00000, a second AL header byte, before the length field, + ** is expected and contains the actual TSID, aligned with MSB */ + if (al_tsid == 0) { + al_tsid = *p++; + } + + /* get remaining media length on base of lcode */ + switch (al_lcode) { + case AVDT_ALH_LCODE_NONE: /* No length field present. Take length from l2cap */ + al_len = (UINT16)(p_end - p); + break; + case AVDT_ALH_LCODE_16BIT: /* 16 bit length field */ + BE_STREAM_TO_UINT16(al_len, p); + break; + case AVDT_ALH_LCODE_9BITM0: /* 9 bit length field, MSB = 0, 8 LSBs in 1 octet following */ + al_len = *p++; + break; + default: /* 9 bit length field, MSB = 1, 8 LSBs in 1 octet following */ + al_len = (UINT16) * p++ + 0x100; + } + + /* max fragment length */ + frag_len = (UINT16)(p_end - p); + /* if it isn't last fragment */ + if (frag_len >= al_len) { + frag_len = al_len; + } + + /* check TSID corresponds to config */ + if (al_tsid != p_scb->curr_cfg.mux_tsid_media) { +#if AVDT_REPORTING == TRUE + if ((p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) && + (al_tsid == p_scb->curr_cfg.mux_tsid_report)) { + /* parse reporting packet */ + p = avdt_scb_hdl_report(p_scb, p, frag_len); + continue; + } else +#endif + { + AVDT_TRACE_WARNING("bad tsid: %d, mux_tsid_media:%d\n", al_tsid, p_scb->curr_cfg.mux_tsid_media); + break; + } + } + /* check are buffer for assembling and related callback set */ + else if ((p_scb->p_media_buf == NULL) || (p_scb->cs.p_media_cback == NULL)) { + AVDT_TRACE_WARNING("NULL p_media_buf or p_media_cback"); + break; + } + + + /* it is media fragment beginning */ + if (!al_frag) { /* is it first fragment of original media packet */ + AVDT_TRACE_DEBUG("al:%d media:%d\n", + al_len, p_scb->media_buf_len); + + p_scb->frag_off = 0; + p_scb->frag_org_len = al_len; /* total length of original media packet */ + /* length check: minimum length of media header is 12 */ + if (p_scb->frag_org_len < 12) { + AVDT_TRACE_WARNING("bad al_len: %d(<12)\n", al_len); + break; + } + /* check that data fit into buffer */ + if (al_len > p_scb->media_buf_len) { + AVDT_TRACE_WARNING("bad al_len: %d(>%d)\n", al_len, p_scb->media_buf_len); + break; + } + /* make sure it is the last fragment in l2cap packet */ + if (p + al_len < p_end) { + AVDT_TRACE_WARNING("bad al_len: %d(>%d)\n", al_len, p_scb->media_buf_len); + break; + } + } else { + AVDT_TRACE_DEBUG("al:%d media:%d frag_org_len:%d frag_off:%d\n", + al_len, p_scb->media_buf_len, p_scb->frag_org_len, p_scb->frag_off); + + /* check that remaining length from AL header equals to original len - length of already received fragments */ + if (al_len != p_scb->frag_org_len - p_scb->frag_off) { + AVDT_TRACE_WARNING("al_len:%d != (frag_org_len:%d - frag_off:%d) %d\n", + al_len, p_scb->frag_org_len, p_scb->frag_off, + (p_scb->frag_org_len - p_scb->frag_off)); + break; + } + + /* do sanity check */ + if (p_scb->frag_off == 0) { + AVDT_TRACE_WARNING("frag_off=0"); + break; + } + } + /* do common sanity check */ + if ((p_scb->frag_org_len <= p_scb->frag_off) || (p_scb->frag_org_len >= p_scb->media_buf_len)) { + AVDT_TRACE_WARNING("common sanity frag_off:%d frag_org_len:%d media_buf_len:%d\n", + p_scb->frag_off, p_scb->frag_org_len, p_scb->media_buf_len); + break; + } + + AVDT_TRACE_DEBUG("Received fragment org_len=%d off=%d al_len=%d frag_len=%d\n", + p_scb->frag_org_len, p_scb->frag_off, al_len, frag_len); + + /* copy fragment into buffer */ + memcpy(p_scb->p_media_buf + p_scb->frag_off, p, frag_len); + p_scb->frag_off += frag_len; + /* move to the next fragment */ + p += frag_len; + /* if it is last fragment in original media packet then process total media pocket */ + if (p_scb->frag_off == p_scb->frag_org_len) { + p_payload = p_scb->p_media_buf; + + /* media header */ + AVDT_MSG_PRS_OCTET1(p_payload, o_v, o_p, o_x, o_cc); + AVDT_MSG_PRS_M_PT(p_payload, m_pt, marker); + BE_STREAM_TO_UINT16(seq, p_payload); + BE_STREAM_TO_UINT32(time_stamp, p_payload); + BE_STREAM_TO_UINT32(ssrc, p_payload); + + UNUSED(o_v); + UNUSED(ssrc); + + /* skip over any csrc's in packet */ + p_payload += o_cc * 4; + + /* check for and skip over extension header */ + if (o_x) { + if (p_scb->p_media_buf + p_scb->frag_off - p_payload < 4) { + AVDT_TRACE_WARNING("length check frag_off:%d p_media_buf:%p p_payload:%p\n", + p_scb->frag_off, p_scb->p_media_buf, p_payload); + break;/* length check */ + } + p_payload += 2; + BE_STREAM_TO_UINT16(ex_len, p_payload); + p_payload += ex_len * 4; + } + + if (p_payload >= p_scb->p_media_buf + p_scb->frag_off) { + AVDT_TRACE_WARNING("length check2 frag_off:%d p_media_buf:%p p_payload:%p\n", + p_scb->frag_off, p_scb->p_media_buf, p_payload); + break;/* length check */ + } + + /* adjust length for any padding at end of packet */ + if (o_p) { + /* padding length in last byte of packet */ + pad_len = *(p_scb->p_media_buf + p_scb->frag_off - 1); + } else { + pad_len = 0; + } + /* payload length */ + payload_len = (UINT32)(p_scb->p_media_buf + p_scb->frag_off - pad_len - p_payload); + + AVDT_TRACE_DEBUG("Received last fragment header=%d len=%d\n", + p_payload - p_scb->p_media_buf, payload_len); + + /* send total media packet up */ + if (p_scb->cs.p_media_cback != NULL) { + (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb), p_payload, + payload_len, time_stamp, seq, m_pt, marker); + } + } + } /* while(p < p_end) */ + + if (p < p_end) { + AVDT_TRACE_WARNING("*** Got bad media packet"); + } + GKI_freebuf(p_data->p_pkt); +} +#endif + +/******************************************************************************* +** +** Function avdt_scb_hdl_pkt +** +** Description +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ +#if AVDT_REPORTING == TRUE + UINT8 *p; +#endif + +#if AVDT_MULTIPLEXING == TRUE + /* select right function in dependance of is fragmentation supported or not */ + if ( 0 != (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX)) { + avdt_scb_hdl_pkt_frag(p_scb, p_data); + } else +#endif +#if AVDT_REPORTING == TRUE + if (p_data->p_pkt->layer_specific == AVDT_CHAN_REPORT) { + p = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset; + avdt_scb_hdl_report(p_scb, p, p_data->p_pkt->len); + GKI_freebuf(p_data->p_pkt); + } else +#endif + avdt_scb_hdl_pkt_no_frag(p_scb, p_data); +} + +/******************************************************************************* +** +** Function avdt_scb_drop_pkt +** +** Description Drop an incoming media packet. This function is called if +** a media packet is received in any state besides streaming. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_scb); + + GKI_freebuf(p_data->p_pkt); + AVDT_TRACE_ERROR(" avdt_scb_drop_pkt Dropped incoming media packet"); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_reconfig_cmd +** +** Description This function calls the application callback function +** with a reconfiguration indication. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + /* if command not supported */ + if (p_scb->cs.nsc_mask & AVDT_NSC_RECONFIG) { + /* send reject */ + p_data->msg.hdr.err_code = AVDT_ERR_NSC; + p_data->msg.hdr.err_param = 0; + avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, p_data); + } else { + /* store requested configuration */ + memcpy(&p_scb->req_cfg, p_data->msg.reconfig_cmd.p_cfg, sizeof(tAVDT_CFG)); + + /* call application callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + NULL, + AVDT_RECONFIG_IND_EVT, + (tAVDT_CTRL *) &p_data->msg.reconfig_cmd); + } +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_reconfig_rsp +** +** Description This function calls the application callback function +** with a reconfiguration confirm. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + if (p_data->msg.hdr.err_code == 0) { + /* store new configuration */ + if (p_scb->req_cfg.num_codec > 0) { + p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec; + memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE); + } + if (p_scb->req_cfg.num_protect > 0) { + p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect; + memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE); + } + } + + p_data->msg.svccap.p_cfg = &p_scb->curr_cfg; + + /* call application callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + NULL, + AVDT_RECONFIG_CFM_EVT, + (tAVDT_CTRL *) &p_data->msg.svccap); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_security_cmd +** +** Description This function calls the application callback with a +** security indication. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + /* if command not supported */ + if (p_scb->cs.nsc_mask & AVDT_NSC_SECURITY) { + /* send reject */ + p_data->msg.hdr.err_code = AVDT_ERR_NSC; + avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_RSP_EVT, p_data); + } else { + /* call application callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + NULL, + AVDT_SECURITY_IND_EVT, + (tAVDT_CTRL *) &p_data->msg.security_cmd); + } +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_security_rsp +** +** Description This function calls the application callback with a +** security confirm. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + /* call application callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + NULL, + AVDT_SECURITY_CFM_EVT, + (tAVDT_CTRL *) &p_data->msg.security_cmd); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_setconfig_cmd +** +** Description This function marks the SCB as in use and copies the +** configuration and peer SEID to the SCB. It then calls +** the application callback with a configuration indication. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CFG *p_cfg; + + if (!p_scb->in_use) { + p_cfg = p_data->msg.config_cmd.p_cfg; + if (p_scb->cs.cfg.codec_info[AVDT_CODEC_TYPE_INDEX] == p_cfg->codec_info[AVDT_CODEC_TYPE_INDEX]) { + /* set sep as in use */ + p_scb->in_use = TRUE; + + /* copy info to scb */ + p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx); + p_scb->peer_seid = p_data->msg.config_cmd.int_seid; + memcpy(&p_scb->req_cfg, p_cfg, sizeof(tAVDT_CFG)); + /* call app callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), /* handle of scb- which is same as sep handle of bta_av_cb.p_scb*/ + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_CONFIG_IND_EVT, + (tAVDT_CTRL *) &p_data->msg.config_cmd); + } else { + p_data->msg.hdr.err_code = AVDT_ERR_UNSUP_CFG; + p_data->msg.hdr.err_param = 0; + avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), + p_data->msg.hdr.sig_id, &p_data->msg); + } + } else { + avdt_scb_rej_in_use(p_scb, p_data); + } +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_setconfig_rej +** +** Description This function marks the SCB as not in use and calls the +** application callback with an open confirm indicating failure. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + /* clear scb variables */ + avdt_scb_clr_vars(p_scb, p_data); + + /* tell ccb we're done with signaling channel */ + avdt_ccb_event(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_CCB_UL_CLOSE_EVT, NULL); + + /* call application callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + NULL, + AVDT_OPEN_CFM_EVT, + (tAVDT_CTRL *) &p_data->msg.hdr); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_setconfig_rsp +** +** Description This function sends the SCB an AVDT_SCB_API_OPEN_REQ_EVT +** to initiate sending of an open command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_EVT_HDR single; + UNUSED(p_data); + + if (p_scb->p_ccb != NULL) { + /* save configuration */ + memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG)); + + /* initiate open */ + single.seid = p_scb->peer_seid; + avdt_scb_event(p_scb, AVDT_SCB_API_OPEN_REQ_EVT, (tAVDT_SCB_EVT *) &single); + } +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_start_cmd +** +** Description This function calls the application callback with a +** start indication. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_data); + + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_START_IND_EVT, + NULL); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_start_rsp +** +** Description This function calls the application callback with a +** start confirm. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_START_CFM_EVT, + (tAVDT_CTRL *) &p_data->msg.hdr); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_suspend_cmd +** +** Description This function calls the application callback with a suspend +** indication. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_data); + + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_SUSPEND_IND_EVT, + NULL); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_suspend_rsp +** +** Description This function calls the application callback with a suspend +** confirm. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_SUSPEND_CFM_EVT, + (tAVDT_CTRL *) &p_data->msg.hdr); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_tc_close +** +** Description This function is called when the transport channel is +** closed. It marks the SCB as not in use and +** initializes certain SCB parameters. It then sends +** an AVDT_CCB_UL_CLOSE_EVT to the CCB if the SCB +** initiated the close. It then checks to see if the SCB +** is to be removed. If it is it deallocates the SCB. Finally, +** it calls the application callback with a close indication. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UINT8 hdl = avdt_scb_to_hdl(p_scb); + tAVDT_CTRL_CBACK *p_ctrl_cback = p_scb->cs.p_ctrl_cback; + tAVDT_CTRL avdt_ctrl; + UINT8 event; + tAVDT_CCB *p_ccb = p_scb->p_ccb; + BD_ADDR remote_addr; + + + memcpy (remote_addr, p_ccb->peer_addr, BD_ADDR_LEN); + + /* set up hdr */ + avdt_ctrl.hdr.err_code = p_scb->close_code; + avdt_ctrl.hdr.err_param = p_data->close.disc_rsn; + + /* clear sep variables */ + avdt_scb_clr_vars(p_scb, p_data); + p_scb->media_seq = 0; + p_scb->cong = FALSE; + + /* free pkt we're holding, if any */ + if (p_scb->p_pkt != NULL) { + GKI_freebuf(p_scb->p_pkt); + p_scb->p_pkt = NULL; + } + + /* stop transport channel timer */ + btu_stop_timer(&p_scb->timer_entry); + + if ((p_scb->role == AVDT_CLOSE_INT) || (p_scb->role == AVDT_OPEN_INT)) { + /* tell ccb we're done with signaling channel */ + avdt_ccb_event(p_ccb, AVDT_CCB_UL_CLOSE_EVT, NULL); + } + event = (p_scb->role == AVDT_CLOSE_INT) ? AVDT_CLOSE_CFM_EVT : AVDT_CLOSE_IND_EVT; + p_scb->role = AVDT_CLOSE_ACP; + + if (p_scb->remove) { + avdt_scb_dealloc(p_scb, NULL); + } + + /* call app callback */ + (*p_ctrl_cback)(hdl, remote_addr, event, &avdt_ctrl); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_delay_rpt_req +** +** Description This function calls the application callback with a delay +** report. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_delay_rpt_req (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_DELAY_RPT, (tAVDT_MSG *) &p_data->apidelay); +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_delay_rpt_cmd +** +** Description This function calls the application callback with a delay +** report. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_delay_rpt_cmd (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_DELAY_REPORT_EVT, + (tAVDT_CTRL *) &p_data->msg.hdr); + + if (p_scb->p_ccb) { + avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_DELAY_RPT, &p_data->msg); + } else { + avdt_scb_rej_not_in_use(p_scb, p_data); + } +} + +/******************************************************************************* +** +** Function avdt_scb_hdl_delay_rpt_rsp +** +** Description This function calls the application callback with a delay +** report. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_delay_rpt_rsp (tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_DELAY_REPORT_CFM_EVT, + (tAVDT_CTRL *) &p_data->msg.hdr); +} + +#if AVDT_REPORTING == TRUE +/******************************************************************************* +** +** Function avdt_scb_hdl_tc_close_sto +** +** Description This function is called when a channel is closed in OPEN +** state. Check the channel type and process accordingly. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CTRL avdt_ctrl; + /* AVDT_CHAN_SIG does not visit this action */ + if (p_data && p_data->close.type != AVDT_CHAN_MEDIA) { + /* it's reporting or recovery channel, + * the channel close in open state means the peer does not support it */ + if (p_data->close.old_tc_state == AVDT_AD_ST_OPEN) { + avdt_ctrl.hdr.err_code = 0; + avdt_ctrl.hdr.err_param = 0; + /* call app callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_REPORT_DISCONN_EVT, &avdt_ctrl); + } + } else { + /* must be in OPEN state. need to go back to idle */ + avdt_scb_event(p_scb, AVDT_SCB_MSG_ABORT_RSP_EVT, NULL); + avdt_scb_hdl_tc_close(p_scb, p_data); + } +} +#endif + +/******************************************************************************* +** +** Function avdt_scb_hdl_tc_open +** +** Description This function is called when the transport channel is +** opened while in the opening state. It calls the +** application callback with an open indication or open +** confirm depending on who initiated the open procedure. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UINT8 event; +#if AVDT_REPORTING == TRUE + UINT8 role; +#endif + + /* stop transport channel connect timer */ + btu_stop_timer(&p_scb->timer_entry); + + event = (p_scb->role == AVDT_OPEN_INT) ? AVDT_OPEN_CFM_EVT : AVDT_OPEN_IND_EVT; + p_data->open.hdr.err_code = 0; + + AVDT_TRACE_DEBUG("psc_mask: cfg: 0x%x, req:0x%x, cur: 0x%x\n", + p_scb->cs.cfg.psc_mask, p_scb->req_cfg.psc_mask, p_scb->curr_cfg.psc_mask); +#if AVDT_REPORTING == TRUE + if (p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) { + /* open the reporting channel, if both devices support it */ + role = (p_scb->role == AVDT_OPEN_INT) ? AVDT_INT : AVDT_ACP; + avdt_ad_open_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb, role); + } +#endif + + /* call app callback */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + event, + (tAVDT_CTRL *) &p_data->open); +} + +#if AVDT_REPORTING == TRUE +/******************************************************************************* +** +** Function avdt_scb_hdl_tc_open_sto +** +** Description This function is called when the transport channel is +** opened while in the opening state. It calls the +** application callback with an open indication or open +** confirm depending on who initiated the open procedure. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CTRL avdt_ctrl; + /* open reporting channel here, when it is implemented */ + + /* call app callback */ + if (p_data->open.hdr.err_code == AVDT_CHAN_REPORT) { + avdt_ctrl.hdr.err_code = 0; + avdt_ctrl.hdr.err_param = 1; + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + p_scb->p_ccb ? p_scb->p_ccb->peer_addr : NULL, + AVDT_REPORT_CONN_EVT, &avdt_ctrl); + } +} +#endif + +/******************************************************************************* +** +** Function avdt_scb_hdl_write_req_no_frag +** +** Description This function frees the media packet currently stored in +** the SCB, if any. Then it builds a new media packet from +** with the passed in buffer and stores it in the SCB. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_write_req_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UINT8 *p; + UINT32 ssrc; + + /* free packet we're holding, if any; to be replaced with new */ + if (p_scb->p_pkt != NULL) { + GKI_freebuf(p_scb->p_pkt); + + /* this shouldn't be happening */ + AVDT_TRACE_WARNING("Dropped media packet; congested"); + } + + /* build a media packet */ + /* Add RTP header if required */ + if ( !(p_data->apiwrite.opt & AVDT_DATA_OPT_NO_RTP) ) { + ssrc = avdt_scb_gen_ssrc(p_scb); + + p_data->apiwrite.p_buf->len += AVDT_MEDIA_HDR_SIZE; + p_data->apiwrite.p_buf->offset -= AVDT_MEDIA_HDR_SIZE; + p_scb->media_seq++; + p = (UINT8 *)(p_data->apiwrite.p_buf + 1) + p_data->apiwrite.p_buf->offset; + + UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1); + UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt); + UINT16_TO_BE_STREAM(p, p_scb->media_seq); + UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp); + UINT32_TO_BE_STREAM(p, ssrc); + } + + /* store it */ + p_scb->p_pkt = p_data->apiwrite.p_buf; +} + +#if AVDT_MULTIPLEXING == TRUE +/******************************************************************************* +** +** Function avdt_scb_hdl_write_req_frag +** +** Description This function builds a new fragments of media packet from +** the passed in buffers and stores them in the SCB. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_write_req_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UINT8 *p; + UINT32 ssrc; + BT_HDR *p_frag; + + /* free fragments we're holding, if any; it shouldn't happen */ + if (!GKI_queue_is_empty(&p_scb->frag_q)) { + while ((p_frag = (BT_HDR *)GKI_dequeue (&p_scb->frag_q)) != NULL) { + GKI_freebuf(p_frag); + } + + /* this shouldn't be happening */ + AVDT_TRACE_WARNING("*** Dropped media packet; congested"); + } + + /* build a media fragments */ + p_scb->frag_off = p_data->apiwrite.data_len; + p_scb->p_next_frag = p_data->apiwrite.p_data; + + ssrc = avdt_scb_gen_ssrc(p_scb); + + /* get first packet */ + p_frag = (BT_HDR *)GKI_getfirst (&p_data->apiwrite.frag_q); + /* posit on Adaptation Layer header */ + p_frag->len += AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE; + p_frag->offset -= AVDT_AL_HDR_SIZE + AVDT_MEDIA_HDR_SIZE; + p = (UINT8 *)(p_frag + 1) + p_frag->offset; + + /* Adaptation Layer header */ + /* TSID, no-fragment bit and coding of length(in 2 length octets following) */ + *p++ = (p_scb->curr_cfg.mux_tsid_media << 3) | AVDT_ALH_LCODE_16BIT; + + /* length of all remaining transport packet */ + UINT16_TO_BE_STREAM(p, p_frag->layer_specific + AVDT_MEDIA_HDR_SIZE ); + /* media header */ + UINT8_TO_BE_STREAM(p, AVDT_MEDIA_OCTET1); + UINT8_TO_BE_STREAM(p, p_data->apiwrite.m_pt); + UINT16_TO_BE_STREAM(p, p_scb->media_seq); + UINT32_TO_BE_STREAM(p, p_data->apiwrite.time_stamp); + UINT32_TO_BE_STREAM(p, ssrc); + p_scb->media_seq++; + + while ((p_frag = (BT_HDR *)GKI_getnext (p_frag)) != NULL) { + /* posit on Adaptation Layer header */ + p_frag->len += AVDT_AL_HDR_SIZE; + p_frag->offset -= AVDT_AL_HDR_SIZE; + p = (UINT8 *)(p_frag + 1) + p_frag->offset; + /* Adaptation Layer header */ + /* TSID, fragment bit and coding of length(in 2 length octets following) */ + *p++ = (p_scb->curr_cfg.mux_tsid_media << 3) | (AVDT_ALH_FRAG_MASK | AVDT_ALH_LCODE_16BIT); + + /* length of all remaining transport packet */ + UINT16_TO_BE_STREAM(p, p_frag->layer_specific ); + } + + /* store it */ + p_scb->frag_q = p_data->apiwrite.frag_q; +} +#endif + + +/******************************************************************************* +** +** Function avdt_scb_hdl_write_req +** +** Description This function calls one of the two versions of building functions +** for case with and without fragmentation +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ +#if AVDT_MULTIPLEXING == TRUE + if (GKI_queue_is_empty(&p_data->apiwrite.frag_q)) +#endif + avdt_scb_hdl_write_req_no_frag(p_scb, p_data); +#if AVDT_MULTIPLEXING == TRUE + else { + avdt_scb_hdl_write_req_frag(p_scb, p_data); + } +#endif +} + +/******************************************************************************* +** +** Function avdt_scb_snd_abort_req +** +** Description This function sends an abort command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_EVT_HDR hdr; + UNUSED(p_data); + + if (p_scb->p_ccb != NULL) { + p_scb->role = AVDT_CLOSE_INT; + + hdr.seid = p_scb->peer_seid; + + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_ABORT, (tAVDT_MSG *) &hdr); + } +} + +/******************************************************************************* +** +** Function avdt_scb_snd_abort_rsp +** +** Description This function sends an abort response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_scb); + + avdt_msg_send_rsp(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), AVDT_SIG_ABORT, + &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_close_req +** +** Description This function sends a close command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_EVT_HDR hdr; + UNUSED(p_data); + + p_scb->role = AVDT_CLOSE_INT; + + hdr.seid = p_scb->peer_seid; + + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_CLOSE, (tAVDT_MSG *) &hdr); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_stream_close +** +** Description This function sends a close command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ +#if AVDT_MULTIPLEXING == TRUE + BT_HDR *p_frag; + + AVDT_TRACE_WARNING("avdt_scb_snd_stream_close c:%d, off:%d\n", + GKI_queue_length(&p_scb->frag_q), p_scb->frag_off); + /* clean fragments queue */ + while ((p_frag = (BT_HDR *)GKI_dequeue (&p_scb->frag_q)) != NULL) { + GKI_freebuf(p_frag); + } + p_scb->frag_off = 0; +#endif + if (p_scb->p_pkt) { + GKI_freebuf(p_scb->p_pkt); + p_scb->p_pkt = NULL; + } + +#if 0 + if (p_scb->cong) { + p_scb->cong = FALSE; + } + + /* p_scb->curr_cfg.mux_tsid_media == 0 */ +#endif + avdt_scb_snd_close_req(p_scb, p_data); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_close_rsp +** +** Description This function sends a close response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_CLOSE, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_getconfig_req +** +** Description This function sends a get configuration command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_EVT_HDR hdr; + UNUSED(p_data); + + hdr.seid = p_scb->peer_seid; + + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_GETCONFIG, (tAVDT_MSG *) &hdr); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_getconfig_rsp +** +** Description This function sends a get configuration response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_GETCONFIG, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_open_req +** +** Description This function sends an open command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_EVT_HDR hdr; + UNUSED(p_data); + + hdr.seid = p_scb->peer_seid; + + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_OPEN, (tAVDT_MSG *) &hdr); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_open_rsp +** +** Description This function sends an open response message. It also +** calls avdt_ad_open_req() to accept a transport channel +** connection. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + /* notify adaption that we're waiting for transport channel open */ + p_scb->role = AVDT_OPEN_ACP; + avdt_ad_open_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, AVDT_ACP); + + /* send response */ + avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_OPEN, &p_data->msg); + + /* start tc connect timer */ + btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_CONN_TOUT); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_reconfig_req +** +** Description This function stores the configuration parameters in the +** SCB and sends a reconfiguration command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG)); + p_data->msg.hdr.seid = p_scb->peer_seid; + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_RECONFIG, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_reconfig_rsp +** +** Description This function stores the configuration parameters in the +** SCB and sends a reconfiguration response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + if (p_data->msg.hdr.err_code == 0) { + /* store new configuration */ + if (p_scb->req_cfg.num_codec > 0) { + p_scb->curr_cfg.num_codec = p_scb->req_cfg.num_codec; + memcpy(p_scb->curr_cfg.codec_info, p_scb->req_cfg.codec_info, AVDT_CODEC_SIZE); + } + if (p_scb->req_cfg.num_protect > 0) { + p_scb->curr_cfg.num_protect = p_scb->req_cfg.num_protect; + memcpy(p_scb->curr_cfg.protect_info, p_scb->req_cfg.protect_info, AVDT_PROTECT_SIZE); + } + + /* send response */ + avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg); + } else { + /* send reject */ + avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_RECONFIG, &p_data->msg); + } +} + +/******************************************************************************* +** +** Function avdt_scb_snd_security_req +** +** Description This function sends a security command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + p_data->msg.hdr.seid = p_scb->peer_seid; + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SECURITY, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_security_rsp +** +** Description This function sends a security response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + if (p_data->msg.hdr.err_code == 0) { + avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg); + } else { + avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SECURITY, &p_data->msg); + } +} + +/******************************************************************************* +** +** Function avdt_scb_snd_setconfig_rej +** +** Description This function marks the SCB as not in use and sends a +** set configuration reject message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + if (p_scb->p_ccb != NULL) { + avdt_msg_send_rej(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg); + + /* clear scb variables */ + avdt_scb_clr_vars(p_scb, p_data); + } +} + +/******************************************************************************* +** +** Function avdt_scb_snd_setconfig_req +** +** Description This function marks the SCB as in use and copies the +** configuration parameters to the SCB. Then the function +** sends a set configuration command message and initiates +** opening of the signaling channel. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CFG *p_req, *p_cfg; + + /* copy API parameters to scb, set scb as in use */ + p_scb->in_use = TRUE; + p_scb->p_ccb = avdt_ccb_by_idx(p_data->msg.config_cmd.hdr.ccb_idx); + p_scb->peer_seid = p_data->msg.config_cmd.hdr.seid; + p_req = p_data->msg.config_cmd.p_cfg; + p_cfg = &p_scb->cs.cfg; +#if AVDT_MULTIPLEXING == TRUE + p_req->mux_tsid_media = p_cfg->mux_tsid_media; + p_req->mux_tcid_media = p_cfg->mux_tcid_media; + if (p_req->psc_mask & AVDT_PSC_REPORT) { + p_req->mux_tsid_report = p_cfg->mux_tsid_report; + p_req->mux_tcid_report = p_cfg->mux_tcid_report; + } +#endif + memcpy(&p_scb->req_cfg, p_data->msg.config_cmd.p_cfg, sizeof(tAVDT_CFG)); + + avdt_msg_send_cmd(p_scb->p_ccb, p_scb, AVDT_SIG_SETCONFIG, &p_data->msg); + + /* tell ccb to open channel */ + avdt_ccb_event(p_scb->p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL); +} + +/******************************************************************************* +** +** Function avdt_scb_snd_setconfig_rsp +** +** Description This function copies the requested configuration into the +** current configuration and sends a set configuration +** response message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + if (p_scb->p_ccb != NULL) { + memcpy(&p_scb->curr_cfg, &p_scb->req_cfg, sizeof(tAVDT_CFG)); + + avdt_msg_send_rsp(p_scb->p_ccb, AVDT_SIG_SETCONFIG, &p_data->msg); + } +} + +/******************************************************************************* +** +** Function avdt_scb_snd_tc_close +** +** Description This function calls avdt_ad_close_req() to close the +** transport channel for this SCB. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_data); + +#if AVDT_REPORTING == TRUE + if (p_scb->curr_cfg.psc_mask & AVDT_PSC_REPORT) { + avdt_ad_close_req(AVDT_CHAN_REPORT, p_scb->p_ccb, p_scb); + } +#endif + avdt_ad_close_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb); +} + +/******************************************************************************* +** +** Function avdt_scb_cb_err +** +** Description This function calls the application callback function +** indicating an error. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CTRL avdt_ctrl; + UNUSED(p_data); + + /* set error code and parameter */ + avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE; + avdt_ctrl.hdr.err_param = 0; + + /* call callback, using lookup table to get callback event */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), + NULL, + avdt_scb_cback_evt[p_scb->curr_evt], + &avdt_ctrl); +} + +/******************************************************************************* +** +** Function avdt_scb_cong_state +** +** Description This function sets the congestion state of the SCB media +** transport channel. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + p_scb->cong = p_data->llcong; +} + +/******************************************************************************* +** +** Function avdt_scb_rej_state +** +** Description This function sends a reject message to the peer indicating +** incorrect state for the received command message. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_scb); + + p_data->msg.hdr.err_code = AVDT_ERR_BAD_STATE; + p_data->msg.hdr.err_param = 0; + avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), + p_data->msg.hdr.sig_id, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_rej_in_use +** +** Description This function sends a reject message to the peer indicating +** the stream is in use. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_scb); + + p_data->msg.hdr.err_code = AVDT_ERR_IN_USE; + p_data->msg.hdr.err_param = 0; + avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), + p_data->msg.hdr.sig_id, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_rej_not_in_use +** +** Description This function sends a reject message to the peer indicating +** the stream is in use. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_scb); + + p_data->msg.hdr.err_code = AVDT_ERR_NOT_IN_USE; + p_data->msg.hdr.err_param = 0; + avdt_msg_send_rej(avdt_ccb_by_idx(p_data->msg.hdr.ccb_idx), + p_data->msg.hdr.sig_id, &p_data->msg); +} + +/******************************************************************************* +** +** Function avdt_scb_set_remove +** +** Description This function marks an SCB to be removed. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_data); + + p_scb->remove = TRUE; +} + +/******************************************************************************* +** +** Function avdt_scb_free_pkt +** +** Description This function frees the media packet passed in. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CTRL avdt_ctrl; +#if AVDT_MULTIPLEXING == TRUE + BT_HDR *p_frag; +#endif + + /* set error code and parameter */ + avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE; + avdt_ctrl.hdr.err_param = 0; + + /* p_buf can be NULL in case using of fragments queue frag_q */ + if (p_data->apiwrite.p_buf) { + GKI_freebuf(p_data->apiwrite.p_buf); + } + +#if AVDT_MULTIPLEXING == TRUE + /* clean fragments queue */ + while ((p_frag = (BT_HDR *)GKI_dequeue (&p_data->apiwrite.frag_q)) != NULL) { + GKI_freebuf(p_frag); + } +#endif + + AVDT_TRACE_WARNING("Dropped media packet"); + + /* we need to call callback to keep data flow going */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, + &avdt_ctrl); +} + +/******************************************************************************* +** +** Function avdt_scb_clr_pkt +** +** Description This function frees the media packet stored in the SCB. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CTRL avdt_ctrl; + tAVDT_CCB *p_ccb; + UINT8 tcid; + UINT16 lcid; +#if AVDT_MULTIPLEXING == TRUE + BT_HDR *p_frag; +#endif + UNUSED(p_data); + + /* set error code and parameter */ + avdt_ctrl.hdr.err_code = AVDT_ERR_BAD_STATE; + avdt_ctrl.hdr.err_param = 0; + /* flush the media data queued at L2CAP */ + if ((p_ccb = p_scb->p_ccb) != NULL) { + /* get tcid from type, scb */ + tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb); + + lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][tcid].lcid; + L2CA_FlushChannel (lcid, L2CAP_FLUSH_CHANS_ALL); + } + + if (p_scb->p_pkt != NULL) { + GKI_freebuf(p_scb->p_pkt); + p_scb->p_pkt = NULL; + + AVDT_TRACE_DEBUG("Dropped stored media packet"); + + /* we need to call callback to keep data flow going */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, + &avdt_ctrl); + } +#if AVDT_MULTIPLEXING == TRUE + else if (!GKI_queue_is_empty (&p_scb->frag_q)) { + AVDT_TRACE_DEBUG("Dropped fragments queue"); + /* clean fragments queue */ + while ((p_frag = (BT_HDR *)GKI_dequeue (&p_scb->frag_q)) != NULL) { + GKI_freebuf(p_frag); + } + + p_scb->frag_off = 0; + + /* we need to call callback to keep data flow going */ + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, + &avdt_ctrl); + } +#endif +} + + +/******************************************************************************* +** +** Function avdt_scb_chk_snd_pkt +** +** Description This function checks if the SCB is congested, and if not +** congested it sends a stored media packet, if any. After it +** sends the packet it calls the application callback function +** with a write confirm. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + tAVDT_CTRL avdt_ctrl; + BT_HDR *p_pkt; +#if AVDT_MULTIPLEXING == TRUE + BOOLEAN sent = FALSE; + UINT8 res = AVDT_AD_SUCCESS; + tAVDT_SCB_EVT data; +#endif + UNUSED(p_data); + + avdt_ctrl.hdr.err_code = 0; + + if (!p_scb->cong) { + if (p_scb->p_pkt != NULL) { + p_pkt = p_scb->p_pkt; + p_scb->p_pkt = NULL; + avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt); + + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl); + } +#if AVDT_MULTIPLEXING == TRUE + else { +#if 0 + AVDT_TRACE_DEBUG("num_q=%d\n", + L2CA_FlushChannel(avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb)].lcid), + L2CAP_FLUSH_CHANS_GET); +#endif + while ((p_pkt = (BT_HDR *)GKI_dequeue (&p_scb->frag_q)) != NULL) { + sent = TRUE; + AVDT_TRACE_DEBUG("Send fragment len=%d\n", p_pkt->len); + /* fragments queue contains fragment to send */ + res = avdt_ad_write_req(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb, p_pkt); + if (AVDT_AD_CONGESTED == res) { + p_scb->cong = TRUE; + AVDT_TRACE_DEBUG("avdt/l2c congested!!"); + break;/* exit loop if channel became congested */ + } + } + AVDT_TRACE_DEBUG("res=%d left=%d\n", res, p_scb->frag_off); + + if (p_scb->frag_off) { + if (AVDT_AD_SUCCESS == res || GKI_queue_is_empty (&p_scb->frag_q)) { + /* all buffers were sent to L2CAP, compose more to queue */ + avdt_scb_queue_frags(p_scb, &p_scb->p_next_frag, &p_scb->frag_off, &p_scb->frag_q); + if (!GKI_queue_is_empty (&p_scb->frag_q)) { + data.llcong = p_scb->cong; + avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, &data); + } + } + } + + /* Send event AVDT_WRITE_CFM_EVT if it was last fragment */ + else if (sent && GKI_queue_is_empty (&p_scb->frag_q)) { + (*p_scb->cs.p_ctrl_cback)(avdt_scb_to_hdl(p_scb), NULL, AVDT_WRITE_CFM_EVT, &avdt_ctrl); + } + } +#endif + } +} + +/******************************************************************************* +** +** Function avdt_scb_tc_timer +** +** Description This function is called to start a timer when the peer +** initiates closing of the stream. The timer verifies that +** the peer disconnects the transport channel. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_data); + + btu_start_timer(&p_scb->timer_entry, BTU_TTYPE_AVDT_SCB_TC, AVDT_SCB_TC_DISC_TOUT); +} + +/******************************************************************************* +** +** Function avdt_scb_clr_vars +** +** Description This function initializes certain SCB variables. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) +{ + UNUSED(p_data); + + if ((p_scb->cs.tsep == AVDT_TSEP_SNK) && (!p_scb->sink_activated)) { + p_scb->in_use = TRUE; + } else { + p_scb->in_use = FALSE; + } + p_scb->p_ccb = NULL; + p_scb->peer_seid = 0; +} + +#if AVDT_MULTIPLEXING == TRUE +/******************************************************************************* +** +** Function avdt_scb_queue_frags +** +** Description This function breaks media payload into fragments +** and put the fragments in the given queue. +** +** Returns Nothing. +** +*******************************************************************************/ +void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq) +{ + UINT16 lcid; + UINT16 num_frag; + UINT16 mtu_used; + UINT8 *p; + BOOLEAN al_hdr = FALSE; + UINT8 tcid; + tAVDT_TC_TBL *p_tbl; + UINT16 buf_size; + UINT16 offset = AVDT_MEDIA_OFFSET + AVDT_AL_HDR_SIZE; + UINT16 cont_offset = offset - AVDT_MEDIA_HDR_SIZE; + BT_HDR *p_frag; + + tcid = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb); + lcid = avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_scb->p_ccb)][tcid].lcid; + + if ( p_scb->frag_off != 0) { + /* continuing process is usually triggered by un-congest event. + * the number of buffers at L2CAP is very small (if not 0). + * we do not need to L2CA_FlushChannel() */ + offset = cont_offset; + al_hdr = TRUE; + num_frag = AVDT_MAX_FRAG_COUNT; + } else { + num_frag = L2CA_FlushChannel(lcid, L2CAP_FLUSH_CHANS_GET); + AVDT_TRACE_DEBUG("num_q=%d lcid=%d\n", num_frag, lcid); + if (num_frag >= AVDT_MAX_FRAG_COUNT) { + num_frag = 0; + } else { + num_frag = AVDT_MAX_FRAG_COUNT - num_frag; + } + } + + /* look up transport channel table entry to get peer mtu */ + p_tbl = avdt_ad_tc_tbl_by_type(AVDT_CHAN_MEDIA, p_scb->p_ccb, p_scb); + buf_size = p_tbl->peer_mtu + BT_HDR_SIZE; + AVDT_TRACE_DEBUG("peer_mtu: %d, buf_size: %d num_frag=%d\n", + p_tbl->peer_mtu, buf_size, num_frag); + + if (buf_size > AVDT_DATA_POOL_SIZE) { + buf_size = AVDT_DATA_POOL_SIZE; + } + + mtu_used = buf_size - BT_HDR_SIZE; + + while (*p_data_len && num_frag) { + /* allocate buffer for fragment */ + if (NULL == (p_frag = (BT_HDR *)GKI_getbuf(buf_size))) { + AVDT_TRACE_WARNING("avdt_scb_queue_frags len=%d(out of GKI buffers)\n", *p_data_len); + break; + } + /* fill fragment by chunk of media payload */ + p_frag->layer_specific = *p_data_len;/* length of all remaining transport packet */ + p_frag->offset = offset; + /* adjust packet offset for continuing packets */ + offset = cont_offset; + + p_frag->len = mtu_used - p_frag->offset; + if (p_frag->len > *p_data_len) { + p_frag->len = *p_data_len; + } + memcpy((UINT8 *)(p_frag + 1) + p_frag->offset, *pp_data, p_frag->len); + *pp_data += p_frag->len; + *p_data_len -= p_frag->len; + AVDT_TRACE_DEBUG("Prepared fragment len=%d\n", p_frag->len); + + if (al_hdr) { + /* Adaptation Layer header */ + p_frag->len += AVDT_AL_HDR_SIZE; + p_frag->offset -= AVDT_AL_HDR_SIZE; + p = (UINT8 *)(p_frag + 1) + p_frag->offset; + /* TSID, fragment bit and coding of length(in 2 length octets following) */ + *p++ = (p_scb->curr_cfg.mux_tsid_media << 3) | (AVDT_ALH_FRAG_MASK | AVDT_ALH_LCODE_16BIT); + + /* length of all remaining transport packet */ + UINT16_TO_BE_STREAM(p, p_frag->layer_specific ); + } + /* put fragment into gueue */ + GKI_enqueue(pq, p_frag); + num_frag--; + } +} +#endif + +#endif /* #if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/include/avdt_defs.h b/components/bt/bluedroid/stack/avdt/include/avdt_defs.h old mode 100755 new mode 100644 similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/avdt_defs.h rename to components/bt/bluedroid/stack/avdt/include/avdt_defs.h diff --git a/components/bt/bluedroid/stack/avdt/include/avdt_int.h b/components/bt/bluedroid/stack/avdt/include/avdt_int.h new file mode 100644 index 0000000000..5c2939c495 --- /dev/null +++ b/components/bt/bluedroid/stack/avdt/include/avdt_int.h @@ -0,0 +1,744 @@ +/****************************************************************************** + * + * Copyright (C) 2002-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This file contains interfaces which are internal to AVDTP. + * + ******************************************************************************/ +#ifndef AVDT_INT_H +#define AVDT_INT_H + +#include "gki.h" +#include "avdt_api.h" +#include "avdtc_api.h" +#include "avdt_defs.h" +#include "l2c_api.h" +#include "btm_api.h" + +#ifndef AVDT_DEBUG +#define AVDT_DEBUG FALSE +#endif + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* channel types */ +enum { + AVDT_CHAN_SIG, /* signaling channel */ + AVDT_CHAN_MEDIA, /* media channel */ +#if AVDT_REPORTING == TRUE + AVDT_CHAN_REPORT, /* reporting channel */ +#endif + AVDT_CHAN_NUM_TYPES +}; + +/* protocol service capabilities of this AVDTP implementation */ +/* for now multiplexing will be used only for fragmentation */ +#if ((AVDT_MULTIPLEXING == TRUE) && (AVDT_REPORTING == TRUE)) +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_REPORT) +#else /* AVDT_MULTIPLEXING && AVDT_REPORTING */ + +#if (AVDT_MULTIPLEXING == TRUE) +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_MUX) +#else /* AVDT_MULTIPLEXING */ + +#if (AVDT_REPORTING == TRUE) +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS | AVDT_PSC_REPORT) +#else /* AVDT_REPORTING */ +#define AVDT_PSC (AVDT_PSC_TRANS | AVDT_PSC_DELAY_RPT) +#define AVDT_LEG_PSC (AVDT_PSC_TRANS) +#endif /* AVDT_REPORTING */ + +#endif /* AVDT_MULTIPLEXING */ + +#endif /* AVDT_MULTIPLEXING && AVDT_REPORTING */ + +/* initiator/acceptor signaling roles */ +#define AVDT_CLOSE_ACP 0 +#define AVDT_CLOSE_INT 1 +#define AVDT_OPEN_ACP 2 +#define AVDT_OPEN_INT 3 + +/* states for avdt_scb_verify */ +#define AVDT_VERIFY_OPEN 0 +#define AVDT_VERIFY_STREAMING 1 +#define AVDT_VERIFY_SUSPEND 2 +#define AVDT_VERIFY_START 3 + +/* to distinguish CCB events from SCB events */ +#define AVDT_CCB_MKR 0x80 + +/* offset where AVDTP signaling message header starts in message */ +#define AVDT_HDR_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS) + +/* offset where AVDTP signaling message content starts; +** use the size of a start header since it's the largest possible +** layout of signaling message in a buffer is: +** +** | BT_HDR | SCB handles | L2CAP + HCI header | AVDTP header | data ... | +** +** Note that we "hide" the scb handles at the top of the message buffer. +*/ +#define AVDT_MSG_OFFSET (L2CAP_MIN_OFFSET + AVDT_NUM_SEPS + AVDT_LEN_TYPE_START) + +/* scb transport channel connect timeout value */ +#define AVDT_SCB_TC_CONN_TOUT 10 + +/* scb transport channel disconnect timeout value */ +#define AVDT_SCB_TC_DISC_TOUT 10 + +/* maximum number of command retransmissions */ +#ifndef AVDT_RET_MAX +#define AVDT_RET_MAX 1 +#endif + + +/* ccb state machine states */ +enum { + AVDT_CCB_IDLE_ST, + AVDT_CCB_OPENING_ST, + AVDT_CCB_OPEN_ST, + AVDT_CCB_CLOSING_ST +}; + +/* state machine action enumeration list */ +enum { + AVDT_CCB_CHAN_OPEN, + AVDT_CCB_CHAN_CLOSE, + AVDT_CCB_CHK_CLOSE, + AVDT_CCB_HDL_DISCOVER_CMD, + AVDT_CCB_HDL_DISCOVER_RSP, + AVDT_CCB_HDL_GETCAP_CMD, + AVDT_CCB_HDL_GETCAP_RSP, + AVDT_CCB_HDL_START_CMD, + AVDT_CCB_HDL_START_RSP, + AVDT_CCB_HDL_SUSPEND_CMD, + AVDT_CCB_HDL_SUSPEND_RSP, + AVDT_CCB_SND_DISCOVER_CMD, + AVDT_CCB_SND_DISCOVER_RSP, + AVDT_CCB_SND_GETCAP_CMD, + AVDT_CCB_SND_GETCAP_RSP, + AVDT_CCB_SND_START_CMD, + AVDT_CCB_SND_START_RSP, + AVDT_CCB_SND_SUSPEND_CMD, + AVDT_CCB_SND_SUSPEND_RSP, + AVDT_CCB_CLEAR_CMDS, + AVDT_CCB_CMD_FAIL, + AVDT_CCB_FREE_CMD, + AVDT_CCB_CONG_STATE, + AVDT_CCB_RET_CMD, + AVDT_CCB_SND_CMD, + AVDT_CCB_SND_MSG, + AVDT_CCB_SET_RECONN, + AVDT_CCB_CLR_RECONN, + AVDT_CCB_CHK_RECONN, + AVDT_CCB_CHK_TIMER, + AVDT_CCB_SET_CONN, + AVDT_CCB_SET_DISCONN, + AVDT_CCB_DO_DISCONN, + AVDT_CCB_LL_CLOSED, + AVDT_CCB_LL_OPENED, + AVDT_CCB_DEALLOC, + AVDT_CCB_NUM_ACTIONS +}; + +#define AVDT_CCB_IGNORE AVDT_CCB_NUM_ACTIONS + +/* ccb state machine events */ +enum { + AVDT_CCB_API_DISCOVER_REQ_EVT, + AVDT_CCB_API_GETCAP_REQ_EVT, + AVDT_CCB_API_START_REQ_EVT, + AVDT_CCB_API_SUSPEND_REQ_EVT, + AVDT_CCB_API_DISCOVER_RSP_EVT, + AVDT_CCB_API_GETCAP_RSP_EVT, + AVDT_CCB_API_START_RSP_EVT, + AVDT_CCB_API_SUSPEND_RSP_EVT, + AVDT_CCB_API_CONNECT_REQ_EVT, + AVDT_CCB_API_DISCONNECT_REQ_EVT, + AVDT_CCB_MSG_DISCOVER_CMD_EVT, + AVDT_CCB_MSG_GETCAP_CMD_EVT, + AVDT_CCB_MSG_START_CMD_EVT, + AVDT_CCB_MSG_SUSPEND_CMD_EVT, + AVDT_CCB_MSG_DISCOVER_RSP_EVT, + AVDT_CCB_MSG_GETCAP_RSP_EVT, + AVDT_CCB_MSG_START_RSP_EVT, + AVDT_CCB_MSG_SUSPEND_RSP_EVT, + AVDT_CCB_RCVRSP_EVT, + AVDT_CCB_SENDMSG_EVT, + AVDT_CCB_RET_TOUT_EVT, + AVDT_CCB_RSP_TOUT_EVT, + AVDT_CCB_IDLE_TOUT_EVT, + AVDT_CCB_UL_OPEN_EVT, + AVDT_CCB_UL_CLOSE_EVT, + AVDT_CCB_LL_OPEN_EVT, + AVDT_CCB_LL_CLOSE_EVT, + AVDT_CCB_LL_CONG_EVT +}; + + +/* scb state machine states; these state values are private to this module so +** the scb state cannot be read or set by actions functions +*/ +enum { + AVDT_SCB_IDLE_ST, + AVDT_SCB_CONF_ST, + AVDT_SCB_OPENING_ST, + AVDT_SCB_OPEN_ST, + AVDT_SCB_STREAM_ST, + AVDT_SCB_CLOSING_ST +}; + +/* state machine action enumeration list */ +enum { + AVDT_SCB_HDL_ABORT_CMD, + AVDT_SCB_HDL_ABORT_RSP, + AVDT_SCB_HDL_CLOSE_CMD, + AVDT_SCB_HDL_CLOSE_RSP, + AVDT_SCB_HDL_GETCONFIG_CMD, + AVDT_SCB_HDL_GETCONFIG_RSP, + AVDT_SCB_HDL_OPEN_CMD, + AVDT_SCB_HDL_OPEN_REJ, + AVDT_SCB_HDL_OPEN_RSP, + AVDT_SCB_HDL_PKT, + AVDT_SCB_DROP_PKT, + AVDT_SCB_HDL_RECONFIG_CMD, + AVDT_SCB_HDL_RECONFIG_RSP, + AVDT_SCB_HDL_SECURITY_CMD, + AVDT_SCB_HDL_SECURITY_RSP, + AVDT_SCB_HDL_SETCONFIG_CMD, + AVDT_SCB_HDL_SETCONFIG_REJ, + AVDT_SCB_HDL_SETCONFIG_RSP, + AVDT_SCB_HDL_START_CMD, + AVDT_SCB_HDL_START_RSP, + AVDT_SCB_HDL_SUSPEND_CMD, + AVDT_SCB_HDL_SUSPEND_RSP, + AVDT_SCB_HDL_TC_CLOSE, +#if AVDT_REPORTING == TRUE + AVDT_SCB_HDL_TC_CLOSE_STO, +#endif + AVDT_SCB_HDL_TC_OPEN, +#if AVDT_REPORTING == TRUE + AVDT_SCB_HDL_TC_OPEN_STO, +#endif + AVDT_SCB_SND_DELAY_RPT_REQ, + AVDT_SCB_HDL_DELAY_RPT_CMD, + AVDT_SCB_HDL_DELAY_RPT_RSP, + AVDT_SCB_HDL_WRITE_REQ, + AVDT_SCB_SND_ABORT_REQ, + AVDT_SCB_SND_ABORT_RSP, + AVDT_SCB_SND_CLOSE_REQ, + AVDT_SCB_SND_STREAM_CLOSE, + AVDT_SCB_SND_CLOSE_RSP, + AVDT_SCB_SND_GETCONFIG_REQ, + AVDT_SCB_SND_GETCONFIG_RSP, + AVDT_SCB_SND_OPEN_REQ, + AVDT_SCB_SND_OPEN_RSP, + AVDT_SCB_SND_RECONFIG_REQ, + AVDT_SCB_SND_RECONFIG_RSP, + AVDT_SCB_SND_SECURITY_REQ, + AVDT_SCB_SND_SECURITY_RSP, + AVDT_SCB_SND_SETCONFIG_REQ, + AVDT_SCB_SND_SETCONFIG_REJ, + AVDT_SCB_SND_SETCONFIG_RSP, + AVDT_SCB_SND_TC_CLOSE, + AVDT_SCB_CB_ERR, + AVDT_SCB_CONG_STATE, + AVDT_SCB_REJ_STATE, + AVDT_SCB_REJ_IN_USE, + AVDT_SCB_REJ_NOT_IN_USE, + AVDT_SCB_SET_REMOVE, + AVDT_SCB_FREE_PKT, + AVDT_SCB_CLR_PKT, + AVDT_SCB_CHK_SND_PKT, + AVDT_SCB_TC_TIMER, + AVDT_SCB_CLR_VARS, + AVDT_SCB_DEALLOC, + AVDT_SCB_NUM_ACTIONS +}; + +#define AVDT_SCB_IGNORE AVDT_SCB_NUM_ACTIONS + +/* scb state machine events */ +enum { + AVDT_SCB_API_REMOVE_EVT, + AVDT_SCB_API_WRITE_REQ_EVT, + AVDT_SCB_API_GETCONFIG_REQ_EVT, + AVDT_SCB_API_DELAY_RPT_REQ_EVT, + AVDT_SCB_API_SETCONFIG_REQ_EVT, + AVDT_SCB_API_OPEN_REQ_EVT, + AVDT_SCB_API_CLOSE_REQ_EVT, + AVDT_SCB_API_RECONFIG_REQ_EVT, + AVDT_SCB_API_SECURITY_REQ_EVT, + AVDT_SCB_API_ABORT_REQ_EVT, + AVDT_SCB_API_GETCONFIG_RSP_EVT, + AVDT_SCB_API_SETCONFIG_RSP_EVT, + AVDT_SCB_API_SETCONFIG_REJ_EVT, + AVDT_SCB_API_OPEN_RSP_EVT, + AVDT_SCB_API_CLOSE_RSP_EVT, + AVDT_SCB_API_RECONFIG_RSP_EVT, + AVDT_SCB_API_SECURITY_RSP_EVT, + AVDT_SCB_API_ABORT_RSP_EVT, + AVDT_SCB_MSG_SETCONFIG_CMD_EVT, + AVDT_SCB_MSG_GETCONFIG_CMD_EVT, + AVDT_SCB_MSG_OPEN_CMD_EVT, + AVDT_SCB_MSG_START_CMD_EVT, + AVDT_SCB_MSG_SUSPEND_CMD_EVT, + AVDT_SCB_MSG_CLOSE_CMD_EVT, + AVDT_SCB_MSG_ABORT_CMD_EVT, + AVDT_SCB_MSG_RECONFIG_CMD_EVT, + AVDT_SCB_MSG_SECURITY_CMD_EVT, + AVDT_SCB_MSG_DELAY_RPT_CMD_EVT, + AVDT_SCB_MSG_DELAY_RPT_RSP_EVT, + AVDT_SCB_MSG_SETCONFIG_RSP_EVT, + AVDT_SCB_MSG_GETCONFIG_RSP_EVT, + AVDT_SCB_MSG_OPEN_RSP_EVT, + AVDT_SCB_MSG_START_RSP_EVT, + AVDT_SCB_MSG_SUSPEND_RSP_EVT, + AVDT_SCB_MSG_CLOSE_RSP_EVT, + AVDT_SCB_MSG_ABORT_RSP_EVT, + AVDT_SCB_MSG_RECONFIG_RSP_EVT, + AVDT_SCB_MSG_SECURITY_RSP_EVT, + AVDT_SCB_MSG_SETCONFIG_REJ_EVT, + AVDT_SCB_MSG_OPEN_REJ_EVT, + AVDT_SCB_MSG_START_REJ_EVT, + AVDT_SCB_MSG_SUSPEND_REJ_EVT, + AVDT_SCB_TC_TOUT_EVT, + AVDT_SCB_TC_OPEN_EVT, + AVDT_SCB_TC_CLOSE_EVT, + AVDT_SCB_TC_CONG_EVT, + AVDT_SCB_TC_DATA_EVT, + AVDT_SCB_CC_CLOSE_EVT +}; + +/* adaption layer number of stream routing table entries */ +#if AVDT_REPORTING == TRUE +/* 2 channels(1 media, 1 report) for each SEP and one for signalling */ +#define AVDT_NUM_RT_TBL ((AVDT_NUM_SEPS<<1) + 1) +#else +#define AVDT_NUM_RT_TBL (AVDT_NUM_SEPS + 1) +#endif + +/* adaption layer number of transport channel table entries - moved to target.h +#define AVDT_NUM_TC_TBL (AVDT_NUM_SEPS + AVDT_NUM_LINKS) */ + +/* "states" used in transport channel table */ +#define AVDT_AD_ST_UNUSED 0 /* Unused - unallocated */ +#define AVDT_AD_ST_IDLE 1 /* No connection */ +#define AVDT_AD_ST_ACP 2 /* Waiting to accept a connection */ +#define AVDT_AD_ST_INT 3 /* Initiating a connection */ +#define AVDT_AD_ST_CONN 4 /* Waiting for connection confirm */ +#define AVDT_AD_ST_CFG 5 /* Waiting for configuration complete */ +#define AVDT_AD_ST_OPEN 6 /* Channel opened */ +#define AVDT_AD_ST_SEC_INT 7 /* Security process as INT */ +#define AVDT_AD_ST_SEC_ACP 8 /* Security process as ACP */ + +/* Configuration flags. tAVDT_TC_TBL.cfg_flags */ +#define AVDT_L2C_CFG_IND_DONE (1<<0) +#define AVDT_L2C_CFG_CFM_DONE (1<<1) +#define AVDT_L2C_CFG_CONN_INT (1<<2) +#define AVDT_L2C_CFG_CONN_ACP (1<<3) + + +/* result code for avdt_ad_write_req() (L2CA_DataWrite()) */ +#define AVDT_AD_FAILED L2CAP_DW_FAILED /* FALSE */ +#define AVDT_AD_SUCCESS L2CAP_DW_SUCCESS /* TRUE */ +#define AVDT_AD_CONGESTED L2CAP_DW_CONGESTED /* 2 */ + +/***************************************************************************** +** data types +*****************************************************************************/ + +/* msg union of all message parameter types */ +typedef union { + tAVDT_EVT_HDR hdr; + tAVDT_EVT_HDR single; + tAVDT_SETCONFIG config_cmd; + tAVDT_CONFIG reconfig_cmd; + tAVDT_MULTI multi; + tAVDT_SECURITY security_cmd; + tAVDT_DISCOVER discover_rsp; + tAVDT_CONFIG svccap; + tAVDT_SECURITY security_rsp; + tAVDT_DELAY_RPT delay_rpt_cmd; +} tAVDT_MSG; + +/* data type for AVDT_CCB_API_DISCOVER_REQ_EVT */ +typedef struct { + tAVDT_CTRL_CBACK *p_cback; + tAVDT_SEP_INFO *p_sep_info; + UINT8 num_seps; +} tAVDT_CCB_API_DISCOVER; + +/* data type for AVDT_CCB_API_GETCAP_REQ_EVT */ +typedef struct { + tAVDT_EVT_HDR single; + tAVDT_CTRL_CBACK *p_cback; + tAVDT_CFG *p_cfg; +} tAVDT_CCB_API_GETCAP; + +/* data type for AVDT_CCB_API_CONNECT_REQ_EVT */ +typedef struct { + tAVDT_CTRL_CBACK *p_cback; + UINT8 sec_mask; +} tAVDT_CCB_API_CONNECT; + +/* data type for AVDT_CCB_API_DISCONNECT_REQ_EVT */ +typedef struct { + tAVDT_CTRL_CBACK *p_cback; +} tAVDT_CCB_API_DISCONNECT; + +/* union associated with ccb state machine events */ +typedef union { + tAVDT_CCB_API_DISCOVER discover; + tAVDT_CCB_API_GETCAP getcap; + tAVDT_CCB_API_CONNECT connect; + tAVDT_CCB_API_DISCONNECT disconnect; + tAVDT_MSG msg; + BOOLEAN llcong; + UINT8 err_code; +} tAVDT_CCB_EVT; + +/* channel control block type */ +typedef struct { + BD_ADDR peer_addr; /* BD address of peer */ + TIMER_LIST_ENT timer_entry; /* CCB timer list entry */ + BUFFER_Q cmd_q; /* Queue for outgoing command messages */ + BUFFER_Q rsp_q; /* Queue for outgoing response and reject messages */ + tAVDT_CTRL_CBACK *proc_cback; /* Procedure callback function */ + tAVDT_CTRL_CBACK *p_conn_cback; /* Connection/disconnection callback function */ + void *p_proc_data; /* Pointer to data storage for procedure */ + BT_HDR *p_curr_cmd; /* Current command being sent awaiting response */ + BT_HDR *p_curr_msg; /* Current message being sent */ + BT_HDR *p_rx_msg; /* Current message being received */ + BOOLEAN allocated; /* Whether ccb is allocated */ + UINT8 state; /* The CCB state machine state */ + BOOLEAN ll_opened; /* TRUE if LL is opened */ + BOOLEAN proc_busy; /* TRUE when a discover or get capabilities procedure in progress */ + UINT8 proc_param; /* Procedure parameter; either SEID for get capabilities or number of SEPS for discover */ + BOOLEAN cong; /* Whether signaling channel is congested */ + UINT8 label; /* Message header "label" (sequence number) */ + BOOLEAN reconn; /* If TRUE, reinitiate connection after transitioning from CLOSING to IDLE state */ + UINT8 ret_count; /* Command retransmission count */ + UINT8 disc_rsn; /* disconnection reason */ +} tAVDT_CCB; + +/* type for action functions */ +typedef void (*tAVDT_CCB_ACTION)(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); + +/* type for AVDT_SCB_API_WRITE_REQ_EVT */ +typedef struct { + BT_HDR *p_buf; + UINT32 time_stamp; +#if AVDT_MULTIPLEXING == TRUE + BUFFER_Q frag_q; /* Queue for outgoing media fragments. p_buf should be 0 */ + UINT8 *p_data; + UINT32 data_len; +#endif + UINT8 m_pt; + tAVDT_DATA_OPT_MASK opt; +} tAVDT_SCB_APIWRITE; + +/* type for AVDT_SCB_TC_CLOSE_EVT */ +typedef struct { + UINT8 old_tc_state; /* channel state before closed */ + UINT8 tcid; /* TCID */ + UINT8 type; /* channel type */ + UINT8 disc_rsn; /* disconnection reason */ +} tAVDT_SCB_TC_CLOSE; + +/* type for scb event data */ +typedef union { + tAVDT_MSG msg; + tAVDT_SCB_APIWRITE apiwrite; + tAVDT_DELAY_RPT apidelay; + tAVDT_OPEN open; + tAVDT_SCB_TC_CLOSE close; + BOOLEAN llcong; + BT_HDR *p_pkt; +} tAVDT_SCB_EVT; + +/* stream control block type */ +typedef struct { + tAVDT_CS cs; /* stream creation struct */ + tAVDT_CFG curr_cfg; /* current configuration */ + tAVDT_CFG req_cfg; /* requested configuration */ + TIMER_LIST_ENT timer_entry; /* timer entry */ + BT_HDR *p_pkt; /* packet waiting to be sent */ + tAVDT_CCB *p_ccb; /* ccb associated with this scb */ + UINT16 media_seq; /* media packet sequence number */ + BOOLEAN allocated; /* whether scb is allocated or unused */ + BOOLEAN in_use; /* whether stream being used by peer */ + BOOLEAN sink_activated; /* A2DP Sink activated/de-activated from Application */ + UINT8 role; /* initiator/acceptor role in current procedure */ + BOOLEAN remove; /* whether CB is marked for removal */ + UINT8 state; /* state machine state */ + UINT8 peer_seid; /* SEID of peer stream */ + UINT8 curr_evt; /* current event; set only by state machine */ + BOOLEAN cong; /* Whether media transport channel is congested */ + UINT8 close_code; /* Error code received in close response */ +#if AVDT_MULTIPLEXING == TRUE + BUFFER_Q frag_q; /* Queue for outgoing media fragments */ + UINT32 frag_off; /* length of already received media fragments */ + UINT32 frag_org_len; /* original length before fragmentation of receiving media packet */ + UINT8 *p_next_frag; /* next fragment to send */ + UINT8 *p_media_buf; /* buffer for media packet assigned by AVDT_SetMediaBuf */ + UINT32 media_buf_len; /* length of buffer for media packet assigned by AVDT_SetMediaBuf */ +#endif +} tAVDT_SCB; + +/* type for action functions */ +typedef void (*tAVDT_SCB_ACTION)(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); + +/* adaption layer type for transport channel table */ +typedef struct { + UINT16 peer_mtu; /* L2CAP mtu of the peer device */ + UINT16 my_mtu; /* Our MTU for this channel */ + UINT16 my_flush_to; /* Our flush timeout for this channel */ + UINT16 lcid; + UINT8 tcid; /* transport channel id */ + UINT8 ccb_idx; /* channel control block associated with this tc */ + UINT8 state; /* transport channel state */ + UINT8 cfg_flags; /* L2CAP configuration flags */ + UINT8 id; +} tAVDT_TC_TBL; + +/* adaption layer type for stream routing table */ +typedef struct { + UINT16 lcid; /* L2CAP LCID of the associated transport channel */ + UINT8 scb_hdl; /* stream control block associated with this tc */ +} tAVDT_RT_TBL; + + +/* adaption layer control block */ +typedef struct { + tAVDT_RT_TBL rt_tbl[AVDT_NUM_LINKS][AVDT_NUM_RT_TBL]; + tAVDT_TC_TBL tc_tbl[AVDT_NUM_TC_TBL]; + UINT8 lcid_tbl[MAX_L2CAP_CHANNELS]; /* map LCID to tc_tbl index */ +} tAVDT_AD; + +/* Control block for AVDT */ +typedef struct { + tAVDT_REG rcb; /* registration control block */ + tAVDT_CCB ccb[AVDT_NUM_LINKS]; /* channel control blocks */ + tAVDT_SCB scb[AVDT_NUM_SEPS]; /* stream control blocks */ + tAVDT_AD ad; /* adaption layer control block */ + tAVDTC_CTRL_CBACK *p_conf_cback; /* conformance callback function */ + tAVDT_CCB_ACTION *p_ccb_act; /* pointer to CCB action functions */ + tAVDT_SCB_ACTION *p_scb_act; /* pointer to SCB action functions */ + tAVDT_CTRL_CBACK *p_conn_cback; /* connection callback function */ + UINT8 trace_level; /* trace level */ +} tAVDT_CB; + + +/***************************************************************************** +** function declarations +*****************************************************************************/ + +/* CCB function declarations */ +extern void avdt_ccb_init(void); +extern void avdt_ccb_event(tAVDT_CCB *p_ccb, UINT8 event, tAVDT_CCB_EVT *p_data); +extern tAVDT_CCB *avdt_ccb_by_bd(BD_ADDR bd_addr); +extern tAVDT_CCB *avdt_ccb_alloc(BD_ADDR bd_addr); +extern void avdt_ccb_dealloc(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern UINT8 avdt_ccb_to_idx(tAVDT_CCB *p_ccb); +extern tAVDT_CCB *avdt_ccb_by_idx(UINT8 idx); + +/* CCB action functions */ +extern void avdt_ccb_chan_open(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chan_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chk_close(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_discover_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_discover_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_getcap_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_getcap_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_start_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_start_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_suspend_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_clear_cmds(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_cmd_fail(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_free_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_cong_state(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_ret_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_cmd(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_snd_msg(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_set_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_clr_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chk_reconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_chk_timer(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_set_conn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_set_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_do_disconn(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_ll_closed(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); +extern void avdt_ccb_ll_opened(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data); + +/* SCB function prototypes */ +extern void avdt_scb_event(tAVDT_SCB *p_scb, UINT8 event, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_init(void); +extern tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs); +extern void avdt_scb_dealloc(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern UINT8 avdt_scb_to_hdl(tAVDT_SCB *p_scb); +extern tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl); +extern UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_seid, UINT8 *p_err_code); +extern void avdt_scb_peer_seid_list(tAVDT_MULTI *p_multi); +extern UINT32 avdt_scb_gen_ssrc(tAVDT_SCB *p_scb); + +/* SCB action functions */ +extern void avdt_scb_hdl_abort_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_close_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_getconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_open_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_open_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_drop_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_reconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_security_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_setconfig_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_start_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_start_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_suspend_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_suspend_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_delay_rpt_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_delay_rpt_cmd(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_delay_rpt_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_open(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_close_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_tc_open_sto(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_hdl_write_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_abort_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_abort_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_close_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_stream_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_close_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_getconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_getconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_open_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_open_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_reconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_reconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_security_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_security_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_setconfig_req(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_setconfig_rej(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_setconfig_rsp(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_snd_tc_close(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_cb_err(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_cong_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_rej_state(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_rej_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_rej_not_in_use(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_set_remove(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_free_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_chk_snd_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_clr_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_tc_timer(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_clr_vars(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data); +extern void avdt_scb_queue_frags(tAVDT_SCB *p_scb, UINT8 **pp_data, UINT32 *p_data_len, BUFFER_Q *pq); + +/* msg function declarations */ +extern BOOLEAN avdt_msg_send(tAVDT_CCB *p_ccb, BT_HDR *p_msg); +extern void avdt_msg_send_cmd(tAVDT_CCB *p_ccb, void *p_scb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_send_rsp(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_send_rej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_send_grej(tAVDT_CCB *p_ccb, UINT8 sig_id, tAVDT_MSG *p_params); +extern void avdt_msg_ind(tAVDT_CCB *p_ccb, BT_HDR *p_buf); + +/* adaption layer function declarations */ +extern void avdt_ad_init(void); +extern UINT8 avdt_ad_type_to_tcid(UINT8 type, tAVDT_SCB *p_scb); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_st(UINT8 type, tAVDT_CCB *p_ccb, UINT8 state); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_lcid(UINT16 lcid); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_alloc(tAVDT_CCB *p_ccb); +extern UINT8 avdt_ad_tc_tbl_to_idx(tAVDT_TC_TBL *p_tbl); +extern void avdt_ad_tc_close_ind(tAVDT_TC_TBL *p_tbl, UINT16 reason); +extern void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl); +extern void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested); +extern void avdt_ad_tc_data_ind(tAVDT_TC_TBL *p_tbl, BT_HDR *p_buf); +extern tAVDT_TC_TBL *avdt_ad_tc_tbl_by_type(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb); +extern UINT8 avdt_ad_write_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, BT_HDR *p_buf); +extern void avdt_ad_open_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb, UINT8 role); +extern void avdt_ad_close_req(UINT8 type, tAVDT_CCB *p_ccb, tAVDT_SCB *p_scb); + +extern void avdt_process_timeout(TIMER_LIST_ENT *p_tle); + +/***************************************************************************** +** macros +*****************************************************************************/ + +/* we store the scb and the label in the layer_specific field of the +** current cmd +*/ +#define AVDT_BLD_LAYERSPEC(ls, msg, label) \ + ls = (((label) << 4) | (msg)) + +#define AVDT_LAYERSPEC_LABEL(ls) ((UINT8)((ls) >> 4)) + +#define AVDT_LAYERSPEC_MSG(ls) ((UINT8)((ls) & 0x000F)) + +/***************************************************************************** +** global data +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif + +/****************************************************************************** +** Main Control Block +*******************************************************************************/ +#if AVDT_DYNAMIC_MEMORY == FALSE +extern tAVDT_CB avdt_cb; +#else +extern tAVDT_CB *avdt_cb_ptr; +#define avdt_cb (*avdt_cb_ptr) +#endif + + +/* L2CAP callback registration structure */ +extern const tL2CAP_APPL_INFO avdt_l2c_appl; + +/* reject message event lookup table */ +extern const UINT8 avdt_msg_rej_2_evt[]; +#ifdef __cplusplus +} +#endif + +#endif /* AVDT_INT_H */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_api.c b/components/bt/bluedroid/stack/avrc/avrc_api.c similarity index 99% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_api.c rename to components/bt/bluedroid/stack/avrc/avrc_api.c index dc10d01179..d619c69388 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_api.c +++ b/components/bt/bluedroid/stack/avrc/avrc_api.c @@ -21,12 +21,16 @@ * Interface to AVRCP mandatory commands * ******************************************************************************/ -#include +// #include #include "bt_trace.h" +#include +#include "bt_target.h" #include "gki.h" #include "avrc_api.h" #include "avrc_int.h" +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) + /***************************************************************************** ** Global data *****************************************************************************/ @@ -1096,3 +1100,4 @@ UINT16 AVRC_PassRsp(UINT8 handle, UINT8 label, tAVRC_MSG_PASS *p_msg) return AVRC_NO_RESOURCES; } +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_bld_ct.c b/components/bt/bluedroid/stack/avrc/avrc_bld_ct.c similarity index 98% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_bld_ct.c rename to components/bt/bluedroid/stack/avrc/avrc_bld_ct.c index 8110a3eb57..692a3ee52a 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_bld_ct.c +++ b/components/bt/bluedroid/stack/avrc/avrc_bld_ct.c @@ -16,12 +16,14 @@ * ******************************************************************************/ #include - +#include "bt_target.h" #include "gki.h" #include "avrc_api.h" #include "avrc_defs.h" #include "avrc_int.h" +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) + /***************************************************************************** ** Global data *****************************************************************************/ @@ -242,3 +244,4 @@ tAVRC_STS AVRC_BldCommand( tAVRC_COMMAND *p_cmd, BT_HDR **pp_pkt) } #endif /* (AVRC_METADATA_INCLUDED == TRUE) */ +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_bld_tg.c b/components/bt/bluedroid/stack/avrc/avrc_bld_tg.c similarity index 99% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_bld_tg.c rename to components/bt/bluedroid/stack/avrc/avrc_bld_tg.c index 1f0a033f87..0ff8692d91 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_bld_tg.c +++ b/components/bt/bluedroid/stack/avrc/avrc_bld_tg.c @@ -16,11 +16,14 @@ * ******************************************************************************/ #include - +#include "bt_target.h" #include "gki.h" #include "avrc_api.h" #include "avrc_defs.h" #include "avrc_int.h" +#include "bt_utils.h" + +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) /***************************************************************************** ** Global data @@ -47,7 +50,7 @@ static tAVRC_STS avrc_bld_get_capability_rsp (tAVRC_GET_CAPS_RSP *p_rsp, BT_HDR tAVRC_STS status = AVRC_STS_NO_ERROR; if (!(AVRC_IS_VALID_CAP_ID(p_rsp->capability_id))) { - AVRC_TRACE_ERROR("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", p_rsp); + AVRC_TRACE_ERROR("avrc_bld_get_capability_rsp bad parameter. p_rsp: %x", (int)p_rsp); status = AVRC_STS_BAD_PARAM; return status; } @@ -299,7 +302,7 @@ static tAVRC_STS avrc_bld_app_setting_text_rsp (tAVRC_GET_APP_ATTR_TXT_RSP *p_rs for (xx = 0; xx < p_rsp->num_attr; xx++) { if (len_left < (p_rsp->p_attrs[xx].str_len + 4)) { - AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp out of room (str_len:%d, left:%d)", + AVRC_TRACE_ERROR("avrc_bld_app_setting_text_rsp out of room %d(str_len:%d, left:%d)", xx, p_rsp->p_attrs[xx].str_len, len_left); p_rsp->num_attr = num_added; sts = AVRC_STS_INTERNAL_ERR; @@ -852,3 +855,4 @@ tAVRC_STS AVRC_BldResponse( UINT8 handle, tAVRC_RESPONSE *p_rsp, BT_HDR **pp_pkt #endif /* (AVRC_METADATA_INCLUDED == TRUE)*/ +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_opt.c b/components/bt/bluedroid/stack/avrc/avrc_opt.c similarity index 98% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_opt.c rename to components/bt/bluedroid/stack/avrc/avrc_opt.c index e628032e64..0c231c0b73 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_opt.c +++ b/components/bt/bluedroid/stack/avrc/avrc_opt.c @@ -21,12 +21,15 @@ * Interface to AVRCP optional commands * ******************************************************************************/ +// #include +#include "bt_target.h" #include -#include "bt_trace.h" #include "gki.h" #include "avrc_api.h" #include "avrc_int.h" +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) + /****************************************************************************** ** ** Function avrc_vendor_msg @@ -227,5 +230,4 @@ UINT16 AVRC_VendorRsp(UINT8 handle, UINT8 label, tAVRC_MSG_VENDOR *p_msg) } } - - +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_pars_ct.c b/components/bt/bluedroid/stack/avrc/avrc_pars_ct.c similarity index 96% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_pars_ct.c rename to components/bt/bluedroid/stack/avrc/avrc_pars_ct.c index 2228bbfe6a..d65935de76 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_pars_ct.c +++ b/components/bt/bluedroid/stack/avrc/avrc_pars_ct.c @@ -16,11 +16,14 @@ * ******************************************************************************/ #include - +#include "bt_target.h" #include "gki.h" #include "avrc_api.h" #include "avrc_defs.h" #include "avrc_int.h" +#include "bt_utils.h" + +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) /***************************************************************************** ** Global data @@ -142,3 +145,5 @@ tAVRC_STS AVRC_ParsResponse (tAVRC_MSG *p_msg, tAVRC_RESPONSE *p_result, UINT8 * #endif /* (AVRC_METADATA_INCLUDED == TRUE) */ + +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_pars_tg.c b/components/bt/bluedroid/stack/avrc/avrc_pars_tg.c similarity index 98% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_pars_tg.c rename to components/bt/bluedroid/stack/avrc/avrc_pars_tg.c index 47f342f632..feecad6446 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_pars_tg.c +++ b/components/bt/bluedroid/stack/avrc/avrc_pars_tg.c @@ -16,12 +16,14 @@ * ******************************************************************************/ #include - +#include "bt_target.h" #include "gki.h" #include "avrc_api.h" #include "avrc_defs.h" #include "avrc_int.h" +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) + /***************************************************************************** ** Global data *****************************************************************************/ @@ -304,3 +306,4 @@ tAVRC_STS AVRC_ParsCommand (tAVRC_MSG *p_msg, tAVRC_COMMAND *p_result, UINT8 *p_ #endif /* (AVRC_METADATA_INCLUDED == TRUE) */ +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_sdp.c b/components/bt/bluedroid/stack/avrc/avrc_sdp.c similarity index 98% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_sdp.c rename to components/bt/bluedroid/stack/avrc/avrc_sdp.c index cd21ae6e5e..4acc8181b6 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_sdp.c +++ b/components/bt/bluedroid/stack/avrc/avrc_sdp.c @@ -22,11 +22,13 @@ * ******************************************************************************/ #include - +#include "bt_target.h" #include "gki.h" #include "avrc_api.h" #include "avrc_int.h" +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) + #ifndef SDP_AVRCP_1_4 #define SDP_AVRCP_1_4 FALSE #endif @@ -350,3 +352,4 @@ void AVRC_Init(void) #endif } +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/avrc_utils.c b/components/bt/bluedroid/stack/avrc/avrc_utils.c similarity index 98% rename from components/bt/bluedroid/btc/profile/std/avrc/avrc_utils.c rename to components/bt/bluedroid/stack/avrc/avrc_utils.c index e307218a02..316edae87c 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/avrc_utils.c +++ b/components/bt/bluedroid/stack/avrc/avrc_utils.c @@ -16,11 +16,12 @@ * ******************************************************************************/ #include - +#include "bt_target.h" #include "gki.h" #include "avrc_api.h" #include "avrc_int.h" +#if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) #if (AVRC_METADATA_INCLUDED == TRUE) @@ -234,3 +235,4 @@ BOOLEAN avrc_is_valid_opcode(UINT8 opcode) #endif /* (AVRC_METADATA_INCLUDED == TRUE) */ +#endif /* #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) */ diff --git a/components/bt/bluedroid/btc/profile/std/avrc/include/avrc_int.h b/components/bt/bluedroid/stack/avrc/include/avrc_int.h similarity index 99% rename from components/bt/bluedroid/btc/profile/std/avrc/include/avrc_int.h rename to components/bt/bluedroid/stack/avrc/include/avrc_int.h index 689692437e..9efafff733 100644 --- a/components/bt/bluedroid/btc/profile/std/avrc/include/avrc_int.h +++ b/components/bt/bluedroid/stack/avrc/include/avrc_int.h @@ -26,7 +26,7 @@ #ifndef AVRC_INT_H #define AVRC_INT_H -//#include "avct_defs.h" +#include "avct_defs.h" #include "avrc_api.h" /* DEBUG FLAGS diff --git a/components/bt/bluedroid/stack/btm/btm_main.c b/components/bt/bluedroid/stack/btm/btm_main.c old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/stack/include/a2d_api.h b/components/bt/bluedroid/stack/include/a2d_api.h new file mode 100644 index 0000000000..2c2f410f61 --- /dev/null +++ b/components/bt/bluedroid/stack/include/a2d_api.h @@ -0,0 +1,255 @@ +/****************************************************************************** + * + * Copyright (C) 2000-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * nterface to A2DP Application Programming Interface + * + ******************************************************************************/ +#ifndef A2D_API_H +#define A2D_API_H +#include "sdp_api.h" + +/***************************************************************************** +** constants +*****************************************************************************/ + +/* Profile supported features */ +#define A2D_SUPF_PLAYER 0x0001 +#define A2D_SUPF_MIC 0x0002 +#define A2D_SUPF_TUNER 0x0004 +#define A2D_SUPF_MIXER 0x0008 + +#define A2D_SUPF_HEADPHONE 0x0001 +#define A2D_SUPF_SPEAKER 0x0002 +#define A2D_SUPF_RECORDER 0x0004 +#define A2D_SUPF_AMP 0x0008 + +/* AV Media Types */ +#define A2D_MEDIA_TYPE_AUDIO 0x00 /* audio media type + RFA */ +#define A2D_MEDIA_TYPE_VIDEO 0x10 /* video media type + RFA */ +#define A2D_MEDIA_TYPE_MULTI 0x20 /* multimedia media type + RFA */ + +/* AV Media Codec Type (Audio Codec ID) */ +#define A2D_MEDIA_CT_SBC 0x00 /* SBC media codec type */ +#define A2D_MEDIA_CT_M12 0x01 /* MPEG-1, 2 Audio media codec type */ +#define A2D_MEDIA_CT_M24 0x02 /* MPEG-2, 4 AAC media codec type */ +#define A2D_MEDIA_CT_ATRAC 0x04 /* ATRAC family media codec type */ + +#define A2D_SUCCESS 0 /* Success */ +#define A2D_FAIL 0x0A /* Failed */ +#define A2D_BUSY 0x0B /* A2D_FindService is already in progress */ +#define A2D_INVALID_PARAMS 0x0C /* bad parameters */ +#define A2D_WRONG_CODEC 0x0D /* wrong codec info */ +#define A2D_BAD_CODEC_TYPE 0xC1 /* Media Codec Type is not valid */ +#define A2D_NS_CODEC_TYPE 0xC2 /* Media Codec Type is not supported */ +#define A2D_BAD_SAMP_FREQ 0xC3 /* Sampling Frequency is not valid or multiple values have been selected */ +#define A2D_NS_SAMP_FREQ 0xC4 /* Sampling Frequency is not supported */ +#define A2D_BAD_CH_MODE 0xC5 /* Channel Mode is not valid or multiple values have been selected */ +#define A2D_NS_CH_MODE 0xC6 /* Channel Mode is not supported */ +#define A2D_BAD_SUBBANDS 0xC7 /* None or multiple values have been selected for Number of Subbands */ +#define A2D_NS_SUBBANDS 0xC8 /* Number of Subbands is not supported */ +#define A2D_BAD_ALLOC_MTHD 0xC9 /* None or multiple values have been selected for Allocation Method */ +#define A2D_NS_ALLOC_MTHD 0xCA /* Allocation Method is not supported */ +#define A2D_BAD_MIN_BITPOOL 0xCB /* Minimum Bitpool Value is not valid */ +#define A2D_NS_MIN_BITPOOL 0xCC /* Minimum Bitpool Value is not supported */ +#define A2D_BAD_MAX_BITPOOL 0xCD /* Maximum Bitpool Value is not valid */ +#define A2D_NS_MAX_BITPOOL 0xCE /* Maximum Bitpool Value is not supported */ +#define A2D_BAD_LAYER 0xCF /* None or multiple values have been selected for Layer */ +#define A2D_NS_LAYER 0xD0 /* Layer is not supported */ +#define A2D_NS_CRC 0xD1 /* CRC is not supported */ +#define A2D_NS_MPF 0xD2 /* MPF-2 is not supported */ +#define A2D_NS_VBR 0xD3 /* VBR is not supported */ +#define A2D_BAD_BIT_RATE 0xD4 /* None or multiple values have been selected for Bit Rate */ +#define A2D_NS_BIT_RATE 0xD5 /* Bit Rate is not supported */ +#define A2D_BAD_OBJ_TYPE 0xD6 /* Either 1) Object type is not valid (b3-b0) or 2) None or multiple values have been selected for Object Type */ +#define A2D_NS_OBJ_TYPE 0xD7 /* Object type is not supported */ +#define A2D_BAD_CHANNEL 0xD8 /* None or multiple values have been selected for Channels */ +#define A2D_NS_CHANNEL 0xD9 /* Channels is not supported */ +#define A2D_BAD_BLOCK_LEN 0xDD /* None or multiple values have been selected for Block Length */ +#define A2D_BAD_CP_TYPE 0xE0 /* The requested CP Type is not supported. */ +#define A2D_BAD_CP_FORMAT 0xE1 /* The format of Content Protection Service Capability/Content Protection Scheme Dependent Data is not correct. */ + +typedef UINT8 tA2D_STATUS; + +/* the return values from A2D_BitsSet() */ +#define A2D_SET_ONE_BIT 1 /* one and only one bit is set */ +#define A2D_SET_ZERO_BIT 0 /* all bits clear */ +#define A2D_SET_MULTL_BIT 2 /* multiple bits are set */ + +/***************************************************************************** +** type definitions +*****************************************************************************/ + +/* This data type is used in A2D_FindService() to initialize the SDP database + * to hold the result service search. */ +typedef struct { + UINT32 db_len; /* Length, in bytes, of the discovery database */ + UINT16 num_attr;/* The number of attributes in p_attrs */ + tSDP_DISCOVERY_DB *p_db; /* Pointer to the discovery database */ + UINT16 *p_attrs; /* The attributes filter. If NULL, A2DP API sets the attribute filter + * to be ATTR_ID_SERVICE_CLASS_ID_LIST, ATTR_ID_BT_PROFILE_DESC_LIST, + * ATTR_ID_SUPPORTED_FEATURES, ATTR_ID_SERVICE_NAME and ATTR_ID_PROVIDER_NAME. + * If not NULL, the input is taken as the filter. */ +} tA2D_SDP_DB_PARAMS; + +/* This data type is used in tA2D_FIND_CBACK to report the result of the SDP discovery process. */ +typedef struct { + UINT16 service_len; /* Length, in bytes, of the service name */ + UINT16 provider_len; /* Length, in bytes, of the provider name */ + char *p_service_name; /* Pointer the service name. This character string may not be null terminated. + * Use the service_len parameter to safely copy this string */ + char *p_provider_name;/* Pointer the provider name. This character string may not be null terminated. + * Use the provider_len parameter to safely copy this string */ + UINT16 features; /* Profile supported features */ + UINT16 avdt_version; /* AVDTP protocol version */ +} tA2D_Service; + +/* This is the callback to notify the result of the SDP discovery process. */ +typedef void (tA2D_FIND_CBACK)(BOOLEAN found, tA2D_Service *p_service); + + +/***************************************************************************** +** external function declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif +/****************************************************************************** +** +** Function A2D_AddRecord +** +** Description This function is called by a server application to add +** SRC or SNK information to an SDP record. Prior to +** calling this function the application must call +** SDP_CreateRecord() to create an SDP record. +** +** Input Parameters: +** service_uuid: Indicates SRC or SNK. +** +** p_service_name: Pointer to a null-terminated character +** string containing the service name. +** +** p_provider_name: Pointer to a null-terminated character +** string containing the provider name. +** +** features: Profile supported features. +** +** sdp_handle: SDP handle returned by SDP_CreateRecord(). +** +** Output Parameters: +** None. +** +** Returns A2D_SUCCESS if function execution succeeded, +** A2D_INVALID_PARAMS if bad parameters are given. +** A2D_FAIL if function execution failed. +** +******************************************************************************/ +extern tA2D_STATUS A2D_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provider_name, + UINT16 features, UINT32 sdp_handle); + +/****************************************************************************** +** +** Function A2D_FindService +** +** Description This function is called by a client application to +** perform service discovery and retrieve SRC or SNK SDP +** record information from a server. Information is +** returned for the first service record found on the +** server that matches the service UUID. The callback +** function will be executed when service discovery is +** complete. There can only be one outstanding call to +** A2D_FindService() at a time; the application must wait +** for the callback before it makes another call to +** the function. +** +** Input Parameters: +** service_uuid: Indicates SRC or SNK. +** +** bd_addr: BD address of the peer device. +** +** p_db: Pointer to the information to initialize +** the discovery database. +** +** p_cback: Pointer to the A2D_FindService() +** callback function. +** +** Output Parameters: +** None. +** +** Returns A2D_SUCCESS if function execution succeeded, +** A2D_INVALID_PARAMS if bad parameters are given. +** A2D_BUSY if discovery is already in progress. +** A2D_FAIL if function execution failed. +** +******************************************************************************/ +extern tA2D_STATUS A2D_FindService(UINT16 service_uuid, BD_ADDR bd_addr, + tA2D_SDP_DB_PARAMS *p_db, tA2D_FIND_CBACK *p_cback); + +/****************************************************************************** +** +** Function A2D_SetTraceLevel +** +** Description Sets the trace level for A2D. If 0xff is passed, the +** current trace level is returned. +** +** Input Parameters: +** new_level: The level to set the A2D tracing to: +** 0xff-returns the current setting. +** 0-turns off tracing. +** >= 1-Errors. +** >= 2-Warnings. +** >= 3-APIs. +** >= 4-Events. +** >= 5-Debug. +** +** Returns The new trace level or current trace level if +** the input parameter is 0xff. +** +******************************************************************************/ +extern UINT8 A2D_SetTraceLevel (UINT8 new_level); + +/****************************************************************************** +** Function A2D_BitsSet +** +** Description Check the given num for the number of bits set +** Returns A2D_SET_ONE_BIT, if one and only one bit is set +** A2D_SET_ZERO_BIT, if all bits clear +** A2D_SET_MULTL_BIT, if multiple bits are set +******************************************************************************/ +extern UINT8 A2D_BitsSet(UINT8 num); + +#ifdef __cplusplus +} +#endif + +/******************************************************************************* +** +** Function A2D_Init +** +** Description This function is called at stack startup to allocate the +** control block (if using dynamic memory), and initializes the +** control block and tracing level. +** +** Returns void +** +*******************************************************************************/ +extern void A2D_Init(void); + +#endif /* A2D_API_H */ diff --git a/components/bt/bluedroid/stack/include/a2d_sbc.h b/components/bt/bluedroid/stack/include/a2d_sbc.h new file mode 100644 index 0000000000..e9dbaa8809 --- /dev/null +++ b/components/bt/bluedroid/stack/include/a2d_sbc.h @@ -0,0 +1,211 @@ +/****************************************************************************** + * + * Copyright (C) 2000-2012 Broadcom Corporation + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * nterface to low complexity subband codec (SBC) + * + ******************************************************************************/ +#ifndef A2D_SBC_H +#define A2D_SBC_H + +/***************************************************************************** +** Constants +*****************************************************************************/ +/* the length of the SBC Media Payload header. */ +#define A2D_SBC_MPL_HDR_LEN 1 + +/* the LOSC of SBC media codec capabilitiy */ +#define A2D_SBC_INFO_LEN 6 + +/* for Codec Specific Information Element */ +#define A2D_SBC_IE_SAMP_FREQ_MSK 0xF0 /* b7-b4 sampling frequency */ +#define A2D_SBC_IE_SAMP_FREQ_16 0x80 /* b7:16 kHz */ +#define A2D_SBC_IE_SAMP_FREQ_32 0x40 /* b6:32 kHz */ +#define A2D_SBC_IE_SAMP_FREQ_44 0x20 /* b5:44.1kHz */ +#define A2D_SBC_IE_SAMP_FREQ_48 0x10 /* b4:48 kHz */ + +#define A2D_SBC_IE_CH_MD_MSK 0x0F /* b3-b0 channel mode */ +#define A2D_SBC_IE_CH_MD_MONO 0x08 /* b3: mono */ +#define A2D_SBC_IE_CH_MD_DUAL 0x04 /* b2: dual */ +#define A2D_SBC_IE_CH_MD_STEREO 0x02 /* b1: stereo */ +#define A2D_SBC_IE_CH_MD_JOINT 0x01 /* b0: joint stereo */ + +#define A2D_SBC_IE_BLOCKS_MSK 0xF0 /* b7-b4 number of blocks */ +#define A2D_SBC_IE_BLOCKS_4 0x80 /* 4 blocks */ +#define A2D_SBC_IE_BLOCKS_8 0x40 /* 8 blocks */ +#define A2D_SBC_IE_BLOCKS_12 0x20 /* 12blocks */ +#define A2D_SBC_IE_BLOCKS_16 0x10 /* 16blocks */ + +#define A2D_SBC_IE_SUBBAND_MSK 0x0C /* b3-b2 number of subbands */ +#define A2D_SBC_IE_SUBBAND_4 0x08 /* b3: 4 */ +#define A2D_SBC_IE_SUBBAND_8 0x04 /* b2: 8 */ + +#define A2D_SBC_IE_ALLOC_MD_MSK 0x03 /* b1-b0 allocation mode */ +#define A2D_SBC_IE_ALLOC_MD_S 0x02 /* b1: SNR */ +#define A2D_SBC_IE_ALLOC_MD_L 0x01 /* b0: loundess */ + +#define A2D_SBC_IE_MIN_BITPOOL 2 +#define A2D_SBC_IE_MAX_BITPOOL 250 + +/* for media payload header */ +#define A2D_SBC_HDR_F_MSK 0x80 +#define A2D_SBC_HDR_S_MSK 0x40 +#define A2D_SBC_HDR_L_MSK 0x20 +#define A2D_SBC_HDR_NUM_MSK 0x0F + +/***************************************************************************** +** Type Definitions +*****************************************************************************/ + +/* data type for the SBC Codec Information Element*/ +typedef struct { + UINT8 samp_freq; /* Sampling frequency */ + UINT8 ch_mode; /* Channel mode */ + UINT8 block_len; /* Block length */ + UINT8 num_subbands; /* Number of subbands */ + UINT8 alloc_mthd; /* Allocation method */ + UINT8 max_bitpool; /* Maximum bitpool */ + UINT8 min_bitpool; /* Minimum bitpool */ +} tA2D_SBC_CIE; + + +/***************************************************************************** +** External Function Declarations +*****************************************************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif +/****************************************************************************** +** +** Function A2D_SbcChkFrInit +** +** Description check if need to init the descramble control block. +** +** Returns nothing. +******************************************************************************/ +extern void A2D_SbcChkFrInit(UINT8 *p_pkt); + +/****************************************************************************** +** +** Function A2D_SbcDescramble +** +** Description descramble the packet. +** +** Returns nothing. +******************************************************************************/ +extern void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len); + +/****************************************************************************** +** +** Function A2D_BldSbcInfo +** +** Description This function is called by an application to build +** the SBC Media Codec Capabilities byte sequence +** beginning from the LOSC octet. +** Input Parameters: +** media_type: Indicates Audio, or Multimedia. +** +** p_ie: The SBC Codec Information Element information. +** +** Output Parameters: +** p_result: the resulting codec info byte sequence. +** +** Returns A2D_SUCCESS if function execution succeeded. +** Error status code, otherwise. +******************************************************************************/ +extern tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie, + UINT8 *p_result); + +/****************************************************************************** +** +** Function A2D_ParsSbcInfo +** +** Description This function is called by an application to parse +** the SBC Media Codec Capabilities byte sequence +** beginning from the LOSC octet. +** Input Parameters: +** p_info: the byte sequence to parse. +** +** for_caps: TRUE, if the byte sequence is for get capabilities response. +** +** Output Parameters: +** p_ie: The SBC Codec Information Element information. +** +** Returns A2D_SUCCESS if function execution succeeded. +** Error status code, otherwise. +******************************************************************************/ +extern tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info, + BOOLEAN for_caps); + +/****************************************************************************** +** +** Function A2D_BldSbcMplHdr +** +** Description This function is called by an application to parse +** the SBC Media Payload header. +** Input Parameters: +** frag: 1, if fragmented. 0, otherwise. +** +** start: 1, if the starting packet of a fragmented frame. +** +** last: 1, if the last packet of a fragmented frame. +** +** num: If frag is 1, this is the number of remaining fragments +** (including this fragment) of this frame. +** If frag is 0, this is the number of frames in this packet. +** +** Output Parameters: +** p_dst: the resulting media payload header byte sequence. +** +** Returns void. +******************************************************************************/ +extern void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start, + BOOLEAN last, UINT8 num); + +/****************************************************************************** +** +** Function A2D_ParsSbcMplHdr +** +** Description This function is called by an application to parse +** the SBC Media Payload header. +** Input Parameters: +** p_src: the byte sequence to parse.. +** +** Output Parameters: +** frag: 1, if fragmented. 0, otherwise. +** +** start: 1, if the starting packet of a fragmented frame. +** +** last: 1, if the last packet of a fragmented frame. +** +** num: If frag is 1, this is the number of remaining fragments +** (including this fragment) of this frame. +** If frag is 0, this is the number of frames in this packet. +** +** Returns void. +******************************************************************************/ +extern void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag, + BOOLEAN *p_start, BOOLEAN *p_last, + UINT8 *p_num); +#ifdef __cplusplus +} +#endif + +#endif /* A2D_SBC_H */ diff --git a/components/bt/bluedroid/btc/profile/std/include/avct_api.h b/components/bt/bluedroid/stack/include/avct_api.h old mode 100755 new mode 100644 similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/avct_api.h rename to components/bt/bluedroid/stack/include/avct_api.h diff --git a/components/bt/bluedroid/btc/profile/std/include/avdt_api.h b/components/bt/bluedroid/stack/include/avdt_api.h similarity index 99% rename from components/bt/bluedroid/btc/profile/std/include/avdt_api.h rename to components/bt/bluedroid/stack/include/avdt_api.h index 59a9db778c..a1e856b6fd 100644 --- a/components/bt/bluedroid/btc/profile/std/include/avdt_api.h +++ b/components/bt/bluedroid/stack/include/avdt_api.h @@ -203,6 +203,9 @@ typedef UINT8 AVDT_REPORT_TYPE; #define AVDT_NSC_RECONFIG 0x02 /* Reconfigure command not supported */ #define AVDT_NSC_SECURITY 0x04 /* Security command not supported */ +/* AVDT disconnection reason */ +#define AVDT_DISC_RSN_NORMAL 0 +#define AVDT_DISC_RSN_ABNORMAL (0xce) /* unintentional disconnection */ /***************************************************************************** ** Type Definitions *****************************************************************************/ diff --git a/components/bt/bluedroid/btc/profile/std/include/avdtc_api.h b/components/bt/bluedroid/stack/include/avdtc_api.h old mode 100755 new mode 100644 similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/avdtc_api.h rename to components/bt/bluedroid/stack/include/avdtc_api.h diff --git a/components/bt/bluedroid/btc/profile/std/include/avrc_api.h b/components/bt/bluedroid/stack/include/avrc_api.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/avrc_api.h rename to components/bt/bluedroid/stack/include/avrc_api.h diff --git a/components/bt/bluedroid/btc/profile/std/include/avrc_defs.h b/components/bt/bluedroid/stack/include/avrc_defs.h similarity index 100% rename from components/bt/bluedroid/btc/profile/std/include/avrc_defs.h rename to components/bt/bluedroid/stack/include/avrc_defs.h diff --git a/components/bt/bluedroid/stack/include/bt_types.h b/components/bt/bluedroid/stack/include/bt_types.h index f211015091..fdcd15629e 100644 --- a/components/bt/bluedroid/stack/include/bt_types.h +++ b/components/bt/bluedroid/stack/include/bt_types.h @@ -41,7 +41,7 @@ typedef int32_t INT32; typedef bool BOOLEAN; #define PACKED __packed -#define INLINE __inline +// #define INLINE __inline #define BCM_STRCPY_S(x1,x2,x3) strcpy((x1),(x3)) #define BCM_STRNCPY_S(x1,x2,x3,x4) strncpy((x1),(x3),(x4)) diff --git a/components/bt/bluedroid/stack/include/dyn_mem.h b/components/bt/bluedroid/stack/include/dyn_mem.h old mode 100755 new mode 100644 index 9a95fb9565..2654316cba --- a/components/bt/bluedroid/stack/include/dyn_mem.h +++ b/components/bt/bluedroid/stack/include/dyn_mem.h @@ -18,6 +18,62 @@ #ifndef DYN_MEM_H #define DYN_MEM_H +#include "sdkconfig.h" +#if CONFIG_CLASSIC_BT_ENABLED + +#define SDP_DYNAMIC_MEMORY FALSE +#define RFC_DYNAMIC_MEMORY FALSE +#define TCS_DYNAMIC_MEMORY FALSE +#define BNEP_DYNAMIC_MEMORY FALSE +#define AVDT_DYNAMIC_MEMORY FALSE +#define AVCT_DYNAMIC_MEMORY FALSE +#define MCA_DYNAMIC_MEMORY FALSE +#define A2D_DYNAMIC_MEMORY FALSE +#define VDP_DYNAMIC_MEMORY FALSE +#define AVRC_DYNAMIC_MEMORY FALSE +#define BIP_DYNAMIC_MEMORY FALSE +#define BPP_DYNAMIC_MEMORY FALSE +#define CTP_DYNAMIC_MEMORY FALSE +#define FTP_DYNAMIC_MEMORY FALSE +#define HCRP_DYNAMIC_MEMORY FALSE +#define HFP_DYNAMIC_MEMORY FALSE +#define HID_DYNAMIC_MEMORY FALSE +#define HSP2_DYNAMIC_MEMORY FALSE +#define ICP_DYNAMIC_MEMORY FALSE +#define OPP_DYNAMIC_MEMORY FALSE +#define PAN_DYNAMIC_MEMORY FALSE +#define SPP_DYNAMIC_MEMORY FALSE +#define SLIP_DYNAMIC_MEMORY FALSE +#define LLCP_DYNAMIC_MEMORY FALSE + +#else /* #if CONFIG_CLASSIC_BT_ENABLED */ + +#define SDP_DYNAMIC_MEMORY TRUE +#define RFC_DYNAMIC_MEMORY TRUE +#define TCS_DYNAMIC_MEMORY TRUE +#define BNEP_DYNAMIC_MEMORY TRUE +#define AVDT_DYNAMIC_MEMORY TRUE +#define AVCT_DYNAMIC_MEMORY TRUE +#define MCA_DYNAMIC_MEMORY TRUE +#define A2D_DYNAMIC_MEMORY TRUE +#define VDP_DYNAMIC_MEMORY TRUE +#define AVRC_DYNAMIC_MEMORY TRUE +#define BIP_DYNAMIC_MEMORY TRUE +#define BPP_DYNAMIC_MEMORY TRUE +#define CTP_DYNAMIC_MEMORY TRUE +#define FTP_DYNAMIC_MEMORY TRUE +#define HCRP_DYNAMIC_MEMORY TRUE +#define HFP_DYNAMIC_MEMORY TRUE +#define HID_DYNAMIC_MEMORY TRUE +#define HSP2_DYNAMIC_MEMORY TRUE +#define ICP_DYNAMIC_MEMORY TRUE +#define OPP_DYNAMIC_MEMORY TRUE +#define PAN_DYNAMIC_MEMORY TRUE +#define SPP_DYNAMIC_MEMORY TRUE +#define SLIP_DYNAMIC_MEMORY TRUE +#define LLCP_DYNAMIC_MEMORY TRUE + +#endif /* #if CONFIG_CLASSIC_BT_ENABLED */ /**************************************************************************** ** Define memory usage for each CORE component (if not defined in bdroid_buildcfg.h) ** The default for each component is to use static memory allocations. @@ -31,8 +87,7 @@ #endif #ifndef SDP_DYNAMIC_MEMORY -//#define SDP_DYNAMIC_MEMORY FALSE -#define SDP_DYNAMIC_MEMORY TRUE +#define SDP_DYNAMIC_MEMORY FALSE #endif #ifndef L2C_DYNAMIC_MEMORY diff --git a/components/bt/bluedroid/stack/include/port_ext.h b/components/bt/bluedroid/stack/include/port_ext.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/stack/include/rfcdefs.h b/components/bt/bluedroid/stack/include/rfcdefs.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/stack/include/sdpdefs.h b/components/bt/bluedroid/stack/include/sdpdefs.h old mode 100755 new mode 100644 diff --git a/components/bt/bluedroid/utils/bt_utils.c b/components/bt/bluedroid/utils/bt_utils.c new file mode 100644 index 0000000000..410b83ea9e --- /dev/null +++ b/components/bt/bluedroid/utils/bt_utils.c @@ -0,0 +1,34 @@ +#include "bt_utils.h" + + +/***************************************************************************** +** +** Function raise_priority_a2dp +** +** Description Raise task priority for A2DP streaming +** +** Returns void +** +*******************************************************************************/ +void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task) +{ + (void) high_task; + return; +} + +/***************************************************************************** +** +** Function adjust_priority_a2dp +** +** Description increase the a2dp consumer task priority temporarily when start +** audio playing, to avoid overflow the audio packet queue, restore +** the a2dp consumer task priority when stop audio playing. +** +** Returns void +** +*******************************************************************************/ +void adjust_priority_a2dp(int start) +{ + (void) start; + return; +} diff --git a/components/bt/bluedroid/utils/include/bt_utils.h b/components/bt/bluedroid/utils/include/bt_utils.h new file mode 100644 index 0000000000..39e2535513 --- /dev/null +++ b/components/bt/bluedroid/utils/include/bt_utils.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * + * Copyright (C) 2009-2012 Broadcom Corporation + * + * 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_UTILS_H +#define BT_UTILS_H + +// static const char BT_UTILS_MODULE[] = "bt_utils_module"; + +/******************************************************************************* +** Type definitions +********************************************************************************/ + +typedef enum { + TASK_HIGH_MEDIA = 0, + TASK_HIGH_GKI_TIMER, + TASK_HIGH_BTU, + TASK_HIGH_HCI_WORKER, + TASK_HIGH_USERIAL_READ, + TASK_UIPC_READ, + TASK_JAVA_ALARM, + TASK_HIGH_MAX +} tHIGH_PRIORITY_TASK; + +/******************************************************************************* +** Functions +********************************************************************************/ + +void raise_priority_a2dp(tHIGH_PRIORITY_TASK high_task); +void adjust_priority_a2dp(int start); +#define UNUSED(x) (void)(x) +#endif /* BT_UTILS_H */ diff --git a/components/bt/component.mk b/components/bt/component.mk index f93cc5204a..8f6ce29d51 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -29,14 +29,17 @@ COMPONENT_ADD_INCLUDEDIRS += bluedroid/bta/include \ bluedroid/gki/include \ bluedroid/hci/include \ bluedroid/osi/include \ + bluedroid/utils/include \ + bluedroid/external/sbc/decoder/include \ bluedroid/btc/core/include \ bluedroid/btc/profile/esp/blufi/include \ bluedroid/btc/profile/esp/include \ bluedroid/btc/profile/std/gatt/include \ bluedroid/btc/profile/std/gap/include \ - bluedroid/btc/profile/std/sdp/include \ + bluedroid/btc/profile/std/a2dp/include \ bluedroid/btc/profile/std/include \ bluedroid/btc/include \ + bluedroid/btif/include \ bluedroid/stack/btm/include \ bluedroid/stack/btu/include \ bluedroid/stack/gap/include \ @@ -45,14 +48,21 @@ COMPONENT_ADD_INCLUDEDIRS += bluedroid/bta/include \ bluedroid/stack/l2cap/include \ bluedroid/stack/sdp/include \ bluedroid/stack/smp/include \ + bluedroid/stack/avct/include \ + bluedroid/stack/avrc/include \ + bluedroid/stack/avdt/include \ + bluedroid/stack/a2dp/include \ bluedroid/stack/include \ - bluedroid/api/include \ + bluedroid/utils/include \ + bluedroid/api/include \ bluedroid/include \ COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/bta/gatt \ bluedroid/bta/hh \ bluedroid/bta/sdp \ + bluedroid/bta/av \ + bluedroid/bta/ar \ bluedroid/bta/sys \ bluedroid/bta \ bluedroid/btcore \ @@ -62,10 +72,13 @@ COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/hci \ bluedroid/main \ bluedroid/osi \ + bluedroid/external/sbc/decoder/srce \ bluedroid/btc/core \ bluedroid/btc/profile/esp/blufi \ bluedroid/btc/profile/std/gap \ bluedroid/btc/profile/std/gatt \ + bluedroid/btc/profile/std/a2dp \ + bluedroid/btc/profile/std/avrc \ bluedroid/btc/profile \ bluedroid/stack/btm \ bluedroid/stack/btu \ @@ -76,7 +89,12 @@ COMPONENT_SRCDIRS += bluedroid/bta/dm \ bluedroid/stack/l2cap \ bluedroid/stack/sdp \ bluedroid/stack/smp \ + bluedroid/stack/avct \ + bluedroid/stack/avrc \ + bluedroid/stack/avdt \ + bluedroid/stack/a2dp \ bluedroid/stack \ + bluedroid/utils \ bluedroid/api \ bluedroid \ diff --git a/docs/api/bluetooth/bt_le.rst b/docs/api/bluetooth/bt_le.rst index 11d09809fe..9535c01da7 100644 --- a/docs/api/bluetooth/bt_le.rst +++ b/docs/api/bluetooth/bt_le.rst @@ -1,4 +1,4 @@ -BT COMMON +BT LE ========= .. toctree:: diff --git a/docs/api/bluetooth/classic_bt.rst b/docs/api/bluetooth/classic_bt.rst new file mode 100644 index 0000000000..59dac87f1b --- /dev/null +++ b/docs/api/bluetooth/classic_bt.rst @@ -0,0 +1,9 @@ +CLASSIC BT +========== + +.. toctree:: + :caption: Classic BT + + BT GAP + BT A2DP + BT AVRC diff --git a/docs/api/bluetooth/esp_a2dp.rst b/docs/api/bluetooth/esp_a2dp.rst new file mode 100644 index 0000000000..24fe4c9535 --- /dev/null +++ b/docs/api/bluetooth/esp_a2dp.rst @@ -0,0 +1,82 @@ +Bluetooth A2DP API +================== + +Overview +-------- + +`Instructions`_ + +.. _Instructions: ../template.html + +Application Example +------------------- + +Check :example:`bluetooth` folder in ESP-IDF examples, which contains the following examples: + +:example:`bluetooth/a2dp_sink` + + This is a A2DP sink client demo. This demo can be discovered and connected by A2DP source device and receive the audio stream from remote device. + + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * :component_file:`bt/bluedroid/api/include/esp_a2dp_api.h` + +Macros +^^^^^^ + +.. doxygendefine:: ESP_A2D_MCT_SBC +.. doxygendefine:: ESP_A2D_MCT_M12 +.. doxygendefine:: ESP_A2D_MCT_M24 +.. doxygendefine:: ESP_A2D_MCT_ATRAC +.. doxygendefine:: ESP_A2D_MCT_NON_A2DP +.. doxygendefine:: ESP_A2D_CIE_LEN_SBC +.. doxygendefine:: ESP_A2D_CIE_LEN_M12 +.. doxygendefine:: ESP_A2D_CIE_LEN_M24 +.. doxygendefine:: ESP_A2D_CIE_LEN_ATRAC + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: esp_a2d_mct_t +.. doxygentypedef:: esp_a2d_cb_t +.. doxygentypedef:: esp_a2d_data_cb_t + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: esp_a2d_connection_state_t +.. doxygenenum:: esp_a2d_disc_rsn_t +.. doxygenenum:: esp_a2d_audio_state_t +.. doxygenenum:: esp_a2d_cb_event_t + +Structures +^^^^^^^^^^ + +.. doxygenstruct:: esp_a2d_cb_param_t + :members: + +.. doxygenstruct:: esp_a2d_cb_param_t::a2d_conn_stat_param + :members: + +.. doxygenstruct:: esp_a2d_cb_param_t::a2d_audio_stat_param + :members: + +.. doxygenstruct:: esp_a2d_cb_param_t::a2d_audio_cfg_param + :members: + + +Functions +^^^^^^^^^ + +.. doxygenfunction:: esp_a2d_register_callback +.. doxygenfunction:: esp_a2d_register_data_callback +.. doxygenfunction:: esp_a2d_sink_init +.. doxygenfunction:: esp_a2d_sink_deinit +.. doxygenfunction:: esp_a2d_sink_connect +.. doxygenfunction:: esp_a2d_sink_disconnect + diff --git a/docs/api/bluetooth/esp_avrc.rst b/docs/api/bluetooth/esp_avrc.rst new file mode 100644 index 0000000000..8e6be37192 --- /dev/null +++ b/docs/api/bluetooth/esp_avrc.rst @@ -0,0 +1,65 @@ +BT AVRCP APIs +============= + +Overview +-------- + +Bluetooth AVRCP reference APIs. + +`Instructions`_ + +Application Example +------------------- + +`Instructions`_ + +.. _Instructions: ../template.html + + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * :component_file:`bt/bluedroid/api/include/esp_avrc_api.h` + + +Macros +^^^^^^ + + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: esp_avrc_ct_cb_t + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: esp_avrc_features_t +.. doxygenenum:: esp_avrc_pt_cmd_t +.. doxygenenum:: esp_avrc_pt_cmd_state_t +.. doxygenenum:: esp_avrc_ct_cb_event_t + +Structures +^^^^^^^^^^ + +.. doxygenstruct:: esp_avrc_ct_cb_param_t + :members: + +.. doxygenstruct:: esp_avrc_ct_cb_param_t::avrc_ct_conn_stat_param + :members: + +.. doxygenstruct:: esp_avrc_ct_cb_param_t::avrc_ct_psth_rsp_param + :members: + + +Functions +^^^^^^^^^ + +.. doxygenfunction:: esp_avrc_ct_register_callback +.. doxygenfunction:: esp_avrc_ct_init +.. doxygenfunction:: esp_avrc_ct_deinit +.. doxygenfunction:: esp_avrc_ct_send_passthrough_cmd + diff --git a/docs/api/bluetooth/esp_bt_device.rst b/docs/api/bluetooth/esp_bt_device.rst index 50e9dcf1a0..8f5a8a4c72 100644 --- a/docs/api/bluetooth/esp_bt_device.rst +++ b/docs/api/bluetooth/esp_bt_device.rst @@ -45,4 +45,5 @@ Functions ^^^^^^^^^ .. doxygenfunction:: esp_bt_dev_get_address +.. doxygenfunction:: esp_bt_dev_set_device_name diff --git a/docs/api/bluetooth/esp_gap_bt.rst b/docs/api/bluetooth/esp_gap_bt.rst new file mode 100644 index 0000000000..8f5314e107 --- /dev/null +++ b/docs/api/bluetooth/esp_gap_bt.rst @@ -0,0 +1,47 @@ +CLASSIC BLUETOOTH GAP API +========================= + +Overview +-------- + +`Instructions`_ + +Application Example +------------------- + +`Instructions`_ + +.. _Instructions: ../template.html + + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * :component_file:`bt/bluedroid/api/include/esp_gap_bt_api.h` + + +Macros +^^^^^^ + + +Type Definitions +^^^^^^^^^^^^^^^^ + + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: esp_bt_scan_mode_t + +Structures +^^^^^^^^^^ + + +Functions +^^^^^^^^^ + +.. doxygenfunction:: esp_bt_gap_set_scan_mode + diff --git a/docs/api/bluetooth/index.rst b/docs/api/bluetooth/index.rst index 996a26e138..db92ee8c2b 100644 --- a/docs/api/bluetooth/index.rst +++ b/docs/api/bluetooth/index.rst @@ -7,6 +7,7 @@ Bluetooth API Bluetooth Controller && VHCI Bluetooth Common Bluetooth LE + Bluetooth Classic BT Example code for this API section is provided in :example:`bluetooth` directory of ESP-IDF examples. diff --git a/examples/bluetooth/a2dp_sink/Makefile b/examples/bluetooth/a2dp_sink/Makefile new file mode 100755 index 0000000000..2db03bb7b7 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := a2dp_sink + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/bluetooth/a2dp_sink/README.rst b/examples/bluetooth/a2dp_sink/README.rst new file mode 100755 index 0000000000..a1f08c24f8 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/README.rst @@ -0,0 +1,14 @@ +ESP-IDF A2DP-SINK demo +====================== + +Demo of A2DP audio sink role + +This is the demo for user to use ESP_APIs to create a GATT Server. + +Options choose step: + 1. make menuconfig. + 2. enter menuconfig "Component config", choose "Bluetooth" + 3. enter menu Bluetooth, choose "Classic Bluetooth" and do not choose "Release DRAM from Classic BT controller" + 4. choose your options. + +After the program started, other bluetooth devices such as smart phones can discover this device named "ESP_SPEAKER", and after connection is established, audio data can be transmitted and there will occur a count of audio data packets printed. diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_av.c b/examples/bluetooth/a2dp_sink/main/bt_app_av.c new file mode 100644 index 0000000000..bb6bb90c7c --- /dev/null +++ b/examples/bluetooth/a2dp_sink/main/bt_app_av.c @@ -0,0 +1,128 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 +#include +#include +#include +#include "esp_log.h" + +#include "bt_app_core.h" +#include "bt_app_av.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" +#include "esp_gap_bt_api.h" +#include "esp_a2dp_api.h" +#include "esp_avrc_api.h" + +/* a2dp event handler */ +static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param); +/* avrc event handler */ +static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param); + + +static uint32_t m_pkt_cnt = 0; +static esp_a2d_audio_state_t m_audio_state = ESP_A2D_AUDIO_STATE_STOPPED; + +/* callback for A2DP sink */ +void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param) +{ + switch (event) { + case ESP_A2D_CONNECTION_STATE_EVT: + case ESP_A2D_AUDIO_STATE_EVT: + case ESP_A2D_AUDIO_CFG_EVT: { + bt_app_work_dispatch(bt_av_hdl_a2d_evt, event, param, sizeof(esp_a2d_cb_param_t), NULL); + break; + } + default: + ESP_LOGE(BT_AV_TAG, "a2dp invalid cb event: %d", event); + break; + } +} + +void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len) +{ + if (++m_pkt_cnt % 100 == 0) { + ESP_LOGE(BT_AV_TAG, "audio data pkt cnt %u", m_pkt_cnt); + } +} + +void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param) +{ + switch (event) { + case ESP_AVRC_CT_CONNECTION_STATE_EVT: + case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: { + bt_app_work_dispatch(bt_av_hdl_avrc_evt, event, param, sizeof(esp_avrc_ct_cb_param_t), NULL); + break; + } + default: + ESP_LOGE(BT_AV_TAG, "avrc invalid cb event: %d", event); + break; + } +} + +static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param) +{ + ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event); + esp_a2d_cb_param_t *a2d = NULL; + switch (event) { + case ESP_A2D_CONNECTION_STATE_EVT: { + a2d = (esp_a2d_cb_param_t *)(p_param); + ESP_LOGI(BT_AV_TAG, "a2dp conn_state_cb, state %d", a2d->conn_stat.state); + break; + } + case ESP_A2D_AUDIO_STATE_EVT: { + a2d = (esp_a2d_cb_param_t *)(p_param); + ESP_LOGI(BT_AV_TAG, "a2dp audio_state_cb state %d", a2d->audio_stat.state); + m_audio_state = a2d->audio_stat.state; + if (ESP_A2D_AUDIO_STATE_STARTED == a2d->audio_stat.state) { + m_pkt_cnt = 0; + } + break; + } + case ESP_A2D_AUDIO_CFG_EVT: { + a2d = (esp_a2d_cb_param_t *)(p_param); + ESP_LOGI(BT_AV_TAG, "a2dp audio_cfg_cb , codec type %d", a2d->audio_cfg.mcc.type); + // for now only SBC stream is supported + if (a2d->audio_cfg.mcc.type == ESP_A2D_MCT_SBC) { + ESP_LOGI(BT_AV_TAG, "audio player configured"); + } + break; + } + default: + ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event); + break; + } +} + +static void bt_av_hdl_avrc_evt(uint16_t event, void *p_param) +{ + ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event); + esp_avrc_ct_cb_param_t *rc = (esp_avrc_ct_cb_param_t *)(p_param); + switch (event) { + case ESP_AVRC_CT_CONNECTION_STATE_EVT: { + uint8_t *bda = rc->conn_stat.remote_bda; + ESP_LOGI(BT_AV_TAG, "avrc conn_state evt: state %d, feature 0x%x, [%02x:%02x:%02x:%02x:%02x:%02x]", + rc->conn_stat.connected, rc->conn_stat.feat_mask, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]); + break; + } + case ESP_AVRC_CT_PASSTHROUGH_RSP_EVT: { + ESP_LOGI(BT_AV_TAG, "avrc passthrough rsp: key_code 0x%x, key_state %d", rc->psth_rsp.key_code, rc->psth_rsp.key_state); + break; + } + default: + ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event); + break; + } +} diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_av.h b/examples/bluetooth/a2dp_sink/main/bt_app_av.h new file mode 100644 index 0000000000..7300b91346 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/main/bt_app_av.h @@ -0,0 +1,39 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BT_APP_AV_H__ +#define __BT_APP_AV_H__ + +#include +#include "esp_a2dp_api.h" +#include "esp_avrc_api.h" + +#define BT_AV_TAG "BT_AV" + +/** + * @brief callback function for A2DP sink + */ +void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param); + +/** + * @brief callback function for A2DP sink audio data stream + */ +void bt_app_a2d_data_cb(const uint8_t *data, uint32_t len); + +/** + * @brief callback function for AVRCP controller + */ +void bt_app_rc_ct_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param); + +#endif /* __BT_APP_AV_H__*/ diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_core.c b/examples/bluetooth/a2dp_sink/main/bt_app_core.c new file mode 100644 index 0000000000..533dfda2f2 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/main/bt_app_core.c @@ -0,0 +1,119 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 +#include +#include +#include "freertos/xtensa_api.h" +#include "freertos/FreeRTOSConfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "bt_app_core.h" + +static void bt_app_task_handler(void *arg); +static bool bt_app_send_msg(bt_app_msg_t *msg); +static void bt_app_work_dispatched(bt_app_msg_t *msg); + +static xQueueHandle bt_app_task_queue = NULL; +static xTaskHandle bt_app_task_handle = NULL; + +bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback) +{ + ESP_LOGD(BT_APP_CORE_TAG, "%s event 0x%x, param len %d", __func__, event, param_len); + + bt_app_msg_t msg; + memset(&msg, 0, sizeof(bt_app_msg_t)); + + msg.sig = BT_APP_SIG_WORK_DISPATCH; + msg.event = event; + msg.cb = p_cback; + + if (param_len == 0) { + return bt_app_send_msg(&msg); + } else if (p_params && param_len > 0) { + if ((msg.param = malloc(param_len)) != NULL) { + memcpy(msg.param, p_params, param_len); + /* check if caller has provided a copy callback to do the deep copy */ + if (p_copy_cback) { + p_copy_cback(&msg, msg.param, p_params); + } + return bt_app_send_msg(&msg); + } + } + + return false; +} + +static bool bt_app_send_msg(bt_app_msg_t *msg) +{ + if (msg == NULL) { + return false; + } + + if (xQueueSend(bt_app_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) { + ESP_LOGE(BT_APP_CORE_TAG, "%s xQueue send failed", __func__); + return false; + } + return true; +} + +static void bt_app_work_dispatched(bt_app_msg_t *msg) +{ + if (msg->cb) { + msg->cb(msg->event, msg->param); + } +} + +static void bt_app_task_handler(void *arg) +{ + bt_app_msg_t msg; + for (;;) { + if (pdTRUE == xQueueReceive(bt_app_task_queue, &msg, (portTickType)portMAX_DELAY)) { + ESP_LOGD(BT_APP_CORE_TAG, "%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event); + switch (msg.sig) { + case BT_APP_SIG_WORK_DISPATCH: + bt_app_work_dispatched(&msg); + break; + default: + ESP_LOGW(BT_APP_CORE_TAG, "%s, unhandled sig: %d", __func__, msg.sig); + break; + } // switch (msg.sig) + + if (msg.param) { + free(msg.param); + } + } + } +} + +void bt_app_task_start_up(void) +{ + bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t)); + xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, bt_app_task_handle); + return; +} + +void bt_app_task_shut_down(void) +{ + if (bt_app_task_handle) { + vTaskDelete(bt_app_task_handle); + bt_app_task_handle = NULL; + } + if (bt_app_task_queue) { + vQueueDelete(bt_app_task_queue); + bt_app_task_queue = NULL; + } +} diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_core.h b/examples/bluetooth/a2dp_sink/main/bt_app_core.h new file mode 100644 index 0000000000..0238ba4e18 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/main/bt_app_core.h @@ -0,0 +1,53 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 __BT_APP_CORE_H__ +#define __BT_APP_CORE_H__ + +#include +#include +#include + +#define BT_APP_CORE_TAG "BT_APP_CORE" + +#define BT_APP_SIG_WORK_DISPATCH (0x01) + +/** + * @brief handler for the dispatched work + */ +typedef void (* bt_app_cb_t) (uint16_t event, void *param); + +/* message to be sent */ +typedef struct { + uint16_t sig; /*!< signal to bt_app_task */ + uint16_t event; /*!< message event id */ + bt_app_cb_t cb; /*!< context switch callback */ + void *param; /*!< parameter area needs to be last */ +} bt_app_msg_t; + +/** + * @brief parameter deep-copy function to be customized + */ +typedef void (* bt_app_copy_cb_t) (bt_app_msg_t *msg, void *p_dest, void *p_src); + +/** + * @brief work dispatcher for the application task + */ +bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback); + +void bt_app_task_start_up(void); + +void bt_app_task_shut_down(void); + +#endif /* __BT_APP_CORE_H__ */ diff --git a/examples/bluetooth/a2dp_sink/main/component.mk b/examples/bluetooth/a2dp_sink/main/component.mk new file mode 100755 index 0000000000..0b9d7585e7 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + diff --git a/examples/bluetooth/a2dp_sink/main/main.c b/examples/bluetooth/a2dp_sink/main/main.c new file mode 100644 index 0000000000..09bb923542 --- /dev/null +++ b/examples/bluetooth/a2dp_sink/main/main.c @@ -0,0 +1,103 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE 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 +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "esp_system.h" +#include "esp_log.h" + +#include "bt.h" +#include "bt_app_core.h" +#include "bt_app_av.h" +#include "esp_bt_main.h" +#include "esp_bt_device.h" +#include "esp_gap_bt_api.h" +#include "esp_a2dp_api.h" +#include "esp_avrc_api.h" + +/* event for handler "bt_av_hdl_stack_up */ +enum { + BT_APP_EVT_STACK_UP = 0, +}; + +/* handler for bluetooth stack enabled events */ +static void bt_av_hdl_stack_evt(uint16_t event, void *p_param); + + +void app_main() +{ + nvs_flash_init(); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + if (esp_bt_controller_init(&bt_cfg) != ESP_OK) { + ESP_LOGE(BT_AV_TAG, "%s initialize controller failed\n", __func__); + return; + } + + if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) { + ESP_LOGE(BT_AV_TAG, "%s enable controller failed\n", __func__); + return; + } + + if (esp_bluedroid_init() != ESP_OK) { + ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed\n", __func__); + return; + } + + if (esp_bluedroid_enable() != ESP_OK) { + ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed\n", __func__); + return; + } + + /* create application task */ + bt_app_task_start_up(); + + /* Bluetooth device name, connection mode and profile set up */ + bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL); +} + + +static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) +{ + ESP_LOGD(BT_AV_TAG, "%s evt %d", __func__, event); + switch (event) { + case BT_APP_EVT_STACK_UP: { + /* set up device name */ + char *dev_name = "ESP_SPEAKER"; + esp_bt_dev_set_device_name(dev_name); + + /* initialize A2DP sink */ + esp_a2d_register_callback(&bt_app_a2d_cb); + esp_a2d_register_data_callback(bt_app_a2d_data_cb); + esp_a2d_sink_init(); + + /* initialize AVRCP controller */ + esp_avrc_ct_init(); + esp_avrc_ct_register_callback(bt_app_rc_ct_cb); + + /* set discoverable and connectable mode, wait to be connected */ + esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE); + break; + } + default: + ESP_LOGE(BT_AV_TAG, "%s unhandled evt %d", __func__, event); + break; + } +} diff --git a/examples/bluetooth/a2dp_sink/sdkconfig.defaults b/examples/bluetooth/a2dp_sink/sdkconfig.defaults new file mode 100644 index 0000000000..dd570f866e --- /dev/null +++ b/examples/bluetooth/a2dp_sink/sdkconfig.defaults @@ -0,0 +1,5 @@ +# Override some defaults so BT stack is enabled and +# Classic BT is enabled and BT_DRAM_RELEASE is disabled +CONFIG_BT_ENABLED=y +CONFIG_CLASSIC_BT_ENABLED=y +