pinebuds/services/bt_app/app_hfp.cpp

2169 lines
71 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#include "analog.h"
#include "app_audio.h"
#include "app_battery.h"
#include "app_status_ind.h"
#include "audioflinger.h"
#include "bluetooth.h"
#include "cmsis_os.h"
#include "hal_chipid.h"
#include "hal_cmu.h"
#include "hal_timer.h"
#include "hal_trace.h"
#include "hal_uart.h"
#include "lockcqueue.h"
#include "nvrecord.h"
#include "nvrecord_dev.h"
#include "nvrecord_env.h"
#include <stdio.h>
#if defined(NEW_NV_RECORD_ENABLED)
#include "nvrecord_bt.h"
#endif
#include "app_bt.h"
#include "app_bt_func.h"
#include "app_bt_media_manager.h"
#include "app_fp_rfcomm.h"
#include "app_hfp.h"
#include "apps.h"
#include "besbt.h"
#include "bt_if.h"
#include "btapp.h"
#include "cqueue.h"
#include "hfp_api.h"
#include "os_api.h"
#include "resources.h"
#ifdef BT_USB_AUDIO_DUAL_MODE
#include "btusb_audio.h"
#endif
#ifdef __THIRDPARTY
#include "app_thirdparty.h"
#endif
#include "bt_drv_interface.h"
#ifdef __IAG_BLE_INCLUDE__
#include "app_ble_mode_switch.h"
#endif
#ifdef VOICE_DATAPATH
#include "app_voicepath.h"
#endif
#include "app.h"
#ifdef __AI_VOICE__
#include "ai_control.h"
#endif
#if defined(IBRT)
#include "app_ibrt_hf.h"
#include "app_ibrt_if.h"
#include "app_tws_ibrt_cmd_sync_hfp_status.h"
#include "besaud_api.h"
#endif
#include "bt_drv_reg_op.h"
#ifdef BISTO_ENABLED
#include "gsound_custom_bt.h"
#endif
#if defined(__BTMAP_ENABLE__)
#include "app_btmap_sms.h"
#endif
#ifdef __INTERCONNECTION__
#define HF_COMMAND_HUAWEI_BATTERY_HEAD "AT+HUAWEIBATTERY="
#define BATTERY_REPORT_NUM 2
#define BATTERY_REPORT_TYPE_BATTERY_LEVEL 1
#define BATTERY_REPORT_KEY_LEFT_BATTERY_LEVEL 2
#define BATTERY_REPORT_KEY_LEFT_CHARGE_STATE 3
char ATCommand[42];
const char *huawei_self_defined_command_response = "+HUAWEIBATTERY=OK";
#endif
/* hfp */
int store_voicebtpcm_m2p_buffer(unsigned char *buf, unsigned int len);
int get_voicebtpcm_p2m_frame(unsigned char *buf, unsigned int len);
int store_voicecvsd_buffer(unsigned char *buf, unsigned int len);
int store_voicemsbc_buffer(unsigned char *buf, unsigned int len);
void btapp_hfp_mic_need_skip_frame_set(int32_t skip_frame);
void a2dp_dual_slave_handling_refresh(void);
void a2dp_dual_slave_setup_during_sco(enum BT_DEVICE_ID_T currentId);
extern "C" bool bt_media_cur_is_bt_stream_media(void);
bool bt_is_sco_media_open();
extern bool app_audio_list_playback_exist(void);
#ifdef GFPS_ENABLED
extern "C" void app_exit_fastpairing_mode(void);
#endif
extern void app_bt_profile_connect_manager_hf(enum BT_DEVICE_ID_T id,
hf_chan_handle_t Chan,
struct hfp_context *ctx);
#ifdef __BT_ONE_BRING_TWO__
extern void hfcall_next_sta_handler(hf_event_t event);
#endif
#ifndef _SCO_BTPCM_CHANNEL_
struct hf_sendbuff_control hf_sendbuff_ctrl;
#endif
#ifdef __INTERACTION__
const char *oppo_self_defined_command_response = "+VDSF:7";
#endif
#if defined(SCO_LOOP)
#define HF_LOOP_CNT (20)
#define HF_LOOP_SIZE (360)
static uint8_t hf_loop_buffer[HF_LOOP_CNT * HF_LOOP_SIZE];
static uint32_t hf_loop_buffer_len[HF_LOOP_CNT];
static uint32_t hf_loop_buffer_valid = 1;
static uint32_t hf_loop_buffer_size = 0;
static char hf_loop_buffer_w_idx = 0;
#endif
static void app_hfp_set_starting_media_pending_flag(bool isEnabled,
uint8_t devId);
void app_hfp_resume_pending_voice_media(void);
static void app_hfp_mediaplay_delay_resume_timer_cb(void const *n) {
app_hfp_resume_pending_voice_media();
}
#define HFP_MEDIAPLAY_DELAY_RESUME_IN_MS \
3000 // This time must be greater than SOUND_CONNECTED play time.
static void app_hfp_mediaplay_delay_resume_timer_cb(void const *n);
osTimerDef(APP_HFP_MEDIAPLAY_DELAY_RESUME_TIMER,
app_hfp_mediaplay_delay_resume_timer_cb);
osTimerId app_hfp_mediaplay_delay_resume_timer_id = NULL;
#ifdef __IAG_BLE_INCLUDE__
static void app_hfp_resume_ble_adv(void);
#endif
#define HFP_AUDIO_CLOSED_DELAY_RESUME_ADV_IN_MS 1500
static void app_hfp_audio_closed_delay_resume_ble_adv_timer_cb(void const *n);
osTimerDef(APP_HFP_AUDIO_CLOSED_DELAY_RESUME_BLE_ADV_TIMER,
app_hfp_audio_closed_delay_resume_ble_adv_timer_cb);
osTimerId app_hfp_audio_closed_delay_resume_ble_adv_timer_id = NULL;
extern struct BT_DEVICE_T app_bt_device;
#if defined(SUPPORT_BATTERY_REPORT) || defined(SUPPORT_HF_INDICATORS)
#ifdef __BT_ONE_BRING_TWO__
static uint8_t battery_level[BT_DEVICE_NUM] = {0xff, 0xff};
#else
static uint8_t battery_level[BT_DEVICE_NUM] = {0xff};
#endif
static uint8_t report_battery_level = 0xff;
void app_hfp_set_battery_level(uint8_t level) {
osapi_lock_stack();
if (report_battery_level == 0xff) {
report_battery_level = level;
osapi_notify_evm();
}
osapi_unlock_stack();
}
int app_hfp_battery_report_reset(uint8_t bt_device_id) {
ASSERT(bt_device_id < BT_DEVICE_NUM, "bt_device_id error");
battery_level[bt_device_id] = 0xff;
return 0;
}
#ifdef __INTERACTION_CUSTOMER_AT_COMMAND__
#define HF_COMMAND_BATTERY_HEAD "AT+VDBTY="
#define HF_COMMAND_VERSION_HEAD "AT+VDRV="
#define HF_COMMAND_FEATURE_HEAD "AT+VDSF="
#define REPORT_NUM 3
#define LEFT_UNIT_REPORT 1
#define RIGHT_UNIT_REPORT 2
#define BOX_REPORT 3
char ATCommand[42];
bt_status_t Send_customer_battery_report_AT_command(hf_chan_handle_t chan_h,
uint8_t level) {
TRACE(0, "Send battery report at commnad.");
/// head and keyNumber
sprintf(ATCommand, "%s%d", HF_COMMAND_BATTERY_HEAD, REPORT_NUM);
/// keys and corresponding values
sprintf(ATCommand, "%s,%d,%d,%d,%d,%d,%d\r", ATCommand, LEFT_UNIT_REPORT,
level, RIGHT_UNIT_REPORT, level, BOX_REPORT, 9);
/// send AT command
return btif_hf_send_at_cmd(chan_h, ATCommand);
}
bt_status_t
Send_customer_phone_feature_support_AT_command(hf_chan_handle_t chan_h,
uint8_t val) {
TRACE(0, "Send_customer_phone_feature_support_AT_command.");
/// keys and corresponding values
sprintf(ATCommand, "%s%d\r", HF_COMMAND_FEATURE_HEAD, val);
/// send AT command
return btif_hf_send_at_cmd(chan_h, ATCommand);
}
bt_status_t Send_customer_version_report_AT_command(hf_chan_handle_t chan_h) {
TRACE(0, "Send version report at commnad.");
/// head and keyNumber
sprintf(ATCommand, "%s%d", HF_COMMAND_VERSION_HEAD, REPORT_NUM);
/// keys and corresponding values
sprintf(ATCommand, "%s,%d,%d,%d,%d,%d,%d\r", ATCommand, LEFT_UNIT_REPORT,
0x1111, RIGHT_UNIT_REPORT, 0x2222, BOX_REPORT, 0x3333);
/// send AT command
return btif_hf_send_at_cmd(chan_h, ATCommand);
}
#endif
#ifdef __INTERCONNECTION__
uint8_t ask_is_selfdefined_battery_report_AT_command_support(void) {
TRACE(0, "ask if mobile support self-defined at commnad.");
uint8_t *pSelfDefinedCommandSupport =
app_battery_get_mobile_support_self_defined_command_p();
*pSelfDefinedCommandSupport = 0;
sprintf(ATCommand, "%s?", HF_COMMAND_HUAWEI_BATTERY_HEAD);
btif_hf_send_at_cmd(
(hf_chan_handle_t)app_bt_device.hf_channel[BT_DEVICE_ID_1], ATCommand);
return 0;
}
uint8_t send_selfdefined_battery_report_AT_command(void) {
uint8_t *pSelfDefinedCommandSupport =
app_battery_get_mobile_support_self_defined_command_p();
uint8_t batteryInfo = 0;
if (*pSelfDefinedCommandSupport) {
app_battery_get_info(NULL, &batteryInfo, NULL);
/// head and keyNumber
sprintf(ATCommand, "%s%d", HF_COMMAND_HUAWEI_BATTERY_HEAD,
BATTERY_REPORT_NUM);
/// keys and corresponding values
sprintf(ATCommand, "%s,%d,%d,%d,%d", ATCommand,
BATTERY_REPORT_KEY_LEFT_BATTERY_LEVEL, batteryInfo & 0x7f,
BATTERY_REPORT_KEY_LEFT_CHARGE_STATE, (batteryInfo & 0x80) ? 1 : 0);
/// send AT command
btif_hf_send_at_cmd(
(hf_chan_handle_t)app_bt_device.hf_channel[BT_DEVICE_ID_1], ATCommand);
}
return 0;
}
#endif
int app_hfp_battery_report(uint8_t level) {
// Care: BT_DEVICE_NUM<-->{0xff, 0xff, ...}
bt_status_t status = BT_STS_LAST_CODE;
hf_chan_handle_t chan;
uint8_t i;
int nRet = 0;
if (level > 9)
return -1;
for (i = 0; i < BT_DEVICE_NUM; i++) {
chan = app_bt_device.hf_channel[i];
if (btif_get_hf_chan_state(chan) == BTIF_HF_STATE_OPEN) {
if (btif_hf_is_hf_indicators_support(chan)) {
if (battery_level[i] != level) {
uint8_t assigned_num = 2; /// battery level assigned num:2
status =
btif_hf_update_indicators_batt_level(chan, assigned_num, level);
}
} else if (btif_hf_is_batt_report_support(chan)) {
if (battery_level[i] != level) {
#ifdef GFPS_ENABLED
app_fp_msg_send_battery_levels();
#endif
#ifdef __INTERACTION_CUSTOMER_AT_COMMAND__
status = Send_customer_battery_report_AT_command(chan, level);
#endif
status = btif_hf_batt_report(chan, level);
}
}
if (BT_STS_PENDING == status) {
battery_level[i] = level;
} else {
nRet = -1;
}
} else {
battery_level[i] = 0xff;
nRet = -1;
}
}
return nRet;
}
void app_hfp_battery_report_proc(void) {
osapi_lock_stack();
if (report_battery_level != 0xff) {
app_hfp_battery_report(report_battery_level);
report_battery_level = 0xff;
}
osapi_unlock_stack();
}
bt_status_t app_hfp_send_at_command(const char *cmd) {
bt_status_t ret = 0;
// send AT command
ret = btif_hf_send_at_cmd(
(hf_chan_handle_t)app_bt_device.hf_channel[BT_DEVICE_ID_1], cmd);
return ret;
}
#endif
void a2dp_get_curStream_remDev(btif_remote_device_t **p_remDev);
bool app_hfp_curr_audio_up(hf_chan_handle_t hfp_chnl) {
int i = 0;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if (app_bt_device.hf_channel[i] == hfp_chnl) {
return app_bt_device.hf_conn_flag[i] &&
app_bt_device.hf_audio_state[i] == BTIF_HF_AUDIO_CON;
}
}
return false;
}
uint8_t app_hfp_get_chnl_via_remDev(hf_chan_handle_t *p_hfp_chnl) {
uint8_t i = 0;
#ifdef __BT_ONE_BRING_TWO__
btif_remote_device_t *p_a2dp_remDev;
btif_remote_device_t *p_hfp_remDev;
a2dp_get_curStream_remDev(&p_a2dp_remDev);
for (i = 0; i < BT_DEVICE_NUM; i++) {
p_hfp_remDev = (btif_remote_device_t *)btif_hf_cmgr_get_remote_device(
app_bt_device.hf_channel[i]);
if (p_hfp_remDev == p_a2dp_remDev)
break;
}
if (i != BT_DEVICE_NUM)
*p_hfp_chnl = app_bt_device.hf_channel[i];
#else
i = BT_DEVICE_ID_1;
*p_hfp_chnl = app_bt_device.hf_channel[i];
#endif
return i;
}
#ifdef SUPPORT_SIRI
int app_hfp_siri_report() {
uint8_t i;
bt_status_t status = BT_STS_LAST_CODE;
hf_chan_handle_t chan;
for (i = 0; i < BT_DEVICE_NUM; i++) {
chan = app_bt_device.hf_channel[i];
if (btif_get_hf_chan_state(chan) == BTIF_HF_STATE_OPEN) {
status = btif_hf_siri_report(chan);
if (status == BT_STS_PENDING) {
return 0;
} else {
return -1;
}
}
}
return 0;
}
extern int open_siri_flag;
int app_hfp_siri_voice(bool en) {
static enum BT_DEVICE_ID_T hf_id = BT_DEVICE_ID_1;
bt_status_t res = BT_STS_LAST_CODE;
hf_chan_handle_t POSSIBLY_UNUSED hf_siri_chnl = NULL;
if (open_siri_flag == 1) {
if (btif_hf_is_voice_rec_active(app_bt_device.hf_channel[hf_id]) == false) {
open_siri_flag = 0;
TRACE(0, "end auto");
} else {
TRACE(0, "need close");
en = false;
}
}
if (open_siri_flag == 0) {
if (btif_hf_is_voice_rec_active(app_bt_device.hf_channel[BT_DEVICE_ID_1]) ==
true) {
TRACE(0, "1 ->close");
hf_id = BT_DEVICE_ID_1;
en = false;
hf_siri_chnl = app_bt_device.hf_channel[BT_DEVICE_ID_1];
}
#ifdef __BT_ONE_BRING_TWO__
else if (btif_hf_is_voice_rec_active(
app_bt_device.hf_channel[BT_DEVICE_ID_2]) == true) {
TRACE(0, "2->close");
hf_id = BT_DEVICE_ID_2;
en = false;
hf_siri_chnl = app_bt_device.hf_channel[BT_DEVICE_ID_2];
}
#endif
else {
open_siri_flag = 1;
en = true;
#ifdef __BT_ONE_BRING_TWO__
hf_id = (enum BT_DEVICE_ID_T)app_hfp_get_chnl_via_remDev(&hf_siri_chnl);
#else
hf_id = BT_DEVICE_ID_1;
#endif
TRACE(1, "a2dp id = %d", hf_id);
}
}
TRACE(4, "[%s]id =%d/%d/%d", __func__, hf_id, open_siri_flag, en);
if (hf_id == BT_DEVICE_NUM)
hf_id = BT_DEVICE_ID_1;
if ((btif_get_hf_chan_state(app_bt_device.hf_channel[hf_id]) ==
BTIF_HF_STATE_OPEN)) {
res = btif_hf_enable_voice_recognition(app_bt_device.hf_channel[hf_id], en);
}
TRACE(3, "[%s] Line =%d, res = %d", __func__, __LINE__, res);
return 0;
}
#endif
#define _THREE_WAY_ONE_CALL_COUNT__ 1
#ifdef _THREE_WAY_ONE_CALL_COUNT__
static enum BT_DEVICE_ID_T hfp_cur_call_chnl = BT_DEVICE_NUM;
static int8_t cur_chnl_call_on_active[BT_DEVICE_NUM] = {0};
int app_bt_get_audio_up_id(void);
void app_hfp_3_way_call_counter_set(enum BT_DEVICE_ID_T id, uint8_t set) {
if (set > 0) {
cur_chnl_call_on_active[id]++;
if (cur_chnl_call_on_active[id] > BT_DEVICE_NUM)
cur_chnl_call_on_active[id] = 2;
} else {
cur_chnl_call_on_active[id]--;
if (cur_chnl_call_on_active[id] < 0)
cur_chnl_call_on_active[id] = 0;
if (app_bt_device.hfchan_call[id] == 1)
cur_chnl_call_on_active[id] = 1;
}
TRACE(1, "call_on_active = %d", cur_chnl_call_on_active[id]);
}
void app_hfp_set_cur_chnl_id(uint8_t id) {
if (hfp_cur_call_chnl == BT_DEVICE_NUM) {
hfp_cur_call_chnl = (enum BT_DEVICE_ID_T)id;
cur_chnl_call_on_active[id] = 1;
}
TRACE(3, "%s hfp_cur_call_chnl = %d id=%d", __func__, hfp_cur_call_chnl,
id);
}
uint8_t app_hfp_get_cur_call_chnl(void **chnl) {
TRACE(2, "%s hfp_cur_call_chnl = %d", __func__, hfp_cur_call_chnl);
if (hfp_cur_call_chnl != BT_DEVICE_NUM) {
return hfp_cur_call_chnl;
}
return BT_DEVICE_NUM;
}
void app_hfp_clear_cur_call_chnl(enum BT_DEVICE_ID_T id) {
hfp_cur_call_chnl = BT_DEVICE_NUM;
cur_chnl_call_on_active[id] = 0;
TRACE(2, "%s id= %d", __func__, id);
}
void app_hfp_cur_call_chnl_reset(enum BT_DEVICE_ID_T id) {
if (id == hfp_cur_call_chnl)
hfp_cur_call_chnl = BT_DEVICE_NUM;
TRACE(3, "%s hfp_cur_call_chnl = %d id=%d", __func__, hfp_cur_call_chnl,
id);
}
bool app_hfp_cur_chnl_is_on_3_way_calling(void) {
uint8_t i = 0;
TRACE(1, "hfp_cur_call_chnl = %d", hfp_cur_call_chnl);
#ifdef __BT_ONE_BRING_TWO__
TRACE(2, "cur_chnl_call_on_active[0] = %d [1] = %d",
cur_chnl_call_on_active[0], cur_chnl_call_on_active[1]);
#else
TRACE(1, "cur_chnl_call_on_active[0] = %d", cur_chnl_call_on_active[0]);
#endif
if (hfp_cur_call_chnl == BT_DEVICE_NUM)
return false;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if (cur_chnl_call_on_active[i] > 1) {
break;
}
}
if (i == BT_DEVICE_NUM)
return false;
return true;
}
#endif
#if defined(__BTIF_EARPHONE__)
static void hfp_app_status_indication(enum BT_DEVICE_ID_T chan_id,
struct hfp_context *ctx) {
#ifdef __BT_ONE_BRING_TWO__
enum BT_DEVICE_ID_T chan_id_other =
(chan_id == BT_DEVICE_ID_1) ? (BT_DEVICE_ID_2) : (BT_DEVICE_ID_1);
#else
enum BT_DEVICE_ID_T chan_id_other = BT_DEVICE_ID_1;
#endif
switch (ctx->event) {
/*
case HF_EVENT_SERVICE_CONNECTED:
break;
case HF_EVENT_SERVICE_DISCONNECTED:
break;
*/
case BTIF_HF_EVENT_CURRENT_CALL_STATE:
TRACE(2, "!!!HF_EVENT_CURRENT_CALL_STATE chan_id:%d, call_number:%s\n",
chan_id, ctx->call_number);
if (app_bt_device.hfchan_callSetup[chan_id] == BTIF_HF_CALL_SETUP_IN) {
//////report incoming call number
// app_status_set_num(ctx->call_number);
#ifdef __BT_WARNING_TONE_MERGE_INTO_STREAM_SBC__
app_voice_report(APP_STATUS_RING_WARNING, chan_id);
#endif
}
break;
case BTIF_HF_EVENT_CALL_IND:
if (ctx->call == BTIF_HF_CALL_NONE &&
app_bt_device.hfchan_call[chan_id] == BTIF_HF_CALL_ACTIVE) {
//////report call hangup voice
TRACE(1,
"!!!HF_EVENT_CALL_IND APP_STATUS_INDICATION_HANGUPCALL "
"chan_id:%d\n",
chan_id);
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP_MEDIA,
BT_STREAM_VOICE, chan_id, 0);
/// disable media prompt
if (app_bt_device.hf_endcall_dis[chan_id] == false) {
TRACE(0, "HANGUPCALL PROMPT");
// app_voice_report(APP_STATUS_INDICATION_HANGUPCALL,chan_id);
}
#if defined(_THREE_WAY_ONE_CALL_COUNT__)
if (app_hfp_get_cur_call_chnl(NULL) == chan_id) {
app_hfp_clear_cur_call_chnl(chan_id);
}
#endif
}
#if defined(_THREE_WAY_ONE_CALL_COUNT__)
else if ((ctx->call == BTIF_HF_CALL_ACTIVE) &&
(app_bt_get_audio_up_id() == chan_id)) {
app_hfp_set_cur_chnl_id(chan_id);
}
#endif
break;
case BTIF_HF_EVENT_CALLSETUP_IND:
if (ctx->call_setup == BTIF_HF_CALL_SETUP_NONE &&
(app_bt_device.hfchan_call[chan_id] != BTIF_HF_CALL_ACTIVE) &&
(app_bt_device.hfchan_callSetup[chan_id] != BTIF_HF_CALL_SETUP_NONE)) {
////check the call refuse and stop media of (ring and call number)
TRACE(1,
"!!!HF_EVENT_CALLSETUP_IND APP_STATUS_INDICATION_REFUSECALL "
"chan_id:%d\n",
chan_id);
#if 0 // def __BT_ONE_BRING_TWO__
if (app_bt_device.hf_audio_state[chan_id_other] == BTIF_HF_AUDIO_DISCON){
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP_MEDIA,BT_STREAM_VOICE,chan_id,0);
app_voice_report(APP_STATUS_INDICATION_REFUSECALL,chan_id);
}
#else
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP_MEDIA,
BT_STREAM_VOICE, chan_id, 0);
#if !defined(IBRT) && defined(MEDIA_PLAYER_SUPPORT)
app_voice_report(APP_STATUS_INDICATION_REFUSECALL,
chan_id); /////////////du<64><75><EFBFBD><EFBFBD>
#endif
#endif
if ((app_bt_device.hfchan_call[chan_id_other] == BTIF_HF_CALL_ACTIVE) &&
(app_bt_device.hf_audio_state[chan_id_other] == BTIF_HF_AUDIO_CON)) {
app_bt_device.curr_hf_channel_id = chan_id_other;
}
} else if (ctx->call_setup == BTIF_HF_CALL_SETUP_NONE &&
(app_bt_device.hfchan_callSetup[chan_id] !=
BTIF_HF_CALL_SETUP_NONE) &&
(app_bt_device.hfchan_call[chan_id] == BTIF_HF_CALL_ACTIVE)) {
TRACE(1,
"!!!HF_EVENT_CALLSETUP_IND APP_STATUS_INDICATION_ANSWERCALL but "
"noneed sco chan_id:%d\n",
chan_id);
#ifdef _THREE_WAY_ONE_CALL_COUNT__
if (app_bt_device.hf_callheld[chan_id] == BTIF_HF_CALL_HELD_NONE) {
if (app_hfp_get_cur_call_chnl(NULL) == chan_id) {
app_hfp_3_way_call_counter_set(chan_id, 0);
}
}
#endif /* _THREE_WAY_ONE_CALL_COUNT__ */
#ifdef MEDIA_PLAYER_SUPPORT
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP_MEDIA,
BT_STREAM_MEDIA, chan_id, 0);
#endif
}
#if defined(_THREE_WAY_ONE_CALL_COUNT__)
else if ((ctx->call_setup != BTIF_HF_CALL_SETUP_NONE) &&
(app_bt_device.hfchan_call[chan_id] == BTIF_HF_CALL_ACTIVE)) {
if (app_hfp_get_cur_call_chnl(NULL) == chan_id) {
app_hfp_3_way_call_counter_set(chan_id, 1);
}
}
#endif
break;
/*
case HF_EVENT_AUDIO_CONNECTED:
TRACE(1,"!!!HF_EVENT_AUDIO_CONNECTED APP_STATUS_INDICATION_ANSWERCALL
chan_id:%d\n",chan_id);
//
app_voice_report(APP_STATUS_INDICATION_ANSWERCALL,chan_id);//////////////duһ<75><D2BB>
break;
*/
case BTIF_HF_EVENT_RING_IND:
#ifdef MEDIA_PLAYER_SUPPORT
app_voice_report(APP_STATUS_INDICATION_INCOMINGCALL, chan_id);
#endif
break;
default:
break;
}
}
#endif
struct BT_DEVICE_ID_DIFF chan_id_flag;
#ifdef __BT_ONE_BRING_TWO__
void hfp_chan_id_distinguish(hf_chan_handle_t chan) {
if (chan == app_bt_device.hf_channel[BT_DEVICE_ID_1]) {
chan_id_flag.id = BT_DEVICE_ID_1;
} else if (chan == app_bt_device.hf_channel[BT_DEVICE_ID_2]) {
chan_id_flag.id = BT_DEVICE_ID_2;
}
}
#endif
int hfp_volume_get(enum BT_DEVICE_ID_T id) {
int vol = TGT_VOLUME_LEVEL_15;
nvrec_btdevicerecord *record = NULL;
bt_bdaddr_t bdAdd;
if (btif_hf_get_remote_bdaddr(app_bt_device.hf_channel[id], &bdAdd) &&
!nv_record_btdevicerecord_find(&bdAdd, &record)) {
vol = record->device_vol.hfp_vol - 2;
} else if (app_audio_manager_hfp_is_active(id)) {
vol = app_bt_stream_hfpvolume_get() - 2;
} else {
vol = TGT_VOLUME_LEVEL_15;
}
if (vol > 15)
vol = 15;
if (vol < 0)
vol = 0;
#ifndef BES_AUTOMATE_TEST
TRACE(2, "hfp get vol raw:%d loc:%d", vol, vol + 2);
#endif
return (vol);
}
void hfp_volume_local_set(enum BT_DEVICE_ID_T id, int8_t vol) {
nvrec_btdevicerecord *record = NULL;
bt_bdaddr_t bdAdd;
if (btif_hf_get_remote_bdaddr(app_bt_device.hf_channel[id], &bdAdd)) {
if (!nv_record_btdevicerecord_find(&bdAdd, &record)) {
nv_record_btdevicerecord_set_hfp_vol(record, vol);
}
}
if (app_bt_stream_volume_get_ptr()->hfp_vol != vol) {
#if defined(NEW_NV_RECORD_ENABLED)
nv_record_btdevicevolume_set_hfp_vol(app_bt_stream_volume_get_ptr(), vol);
#endif
nv_record_touch_cause_flush();
}
}
int hfp_volume_set(enum BT_DEVICE_ID_T id, int vol) {
if (vol > 15)
vol = 15;
if (vol < 0)
vol = 0;
hfp_volume_local_set(id, vol + 2);
if (app_audio_manager_hfp_is_active(id)) {
app_audio_manager_ctrl_volume(APP_AUDIO_MANAGER_VOLUME_CTRL_SET, vol + 2);
}
TRACE(2, "hfp put vol raw:%d loc:%d", vol, vol + 2);
return 0;
}
static uint8_t call_setup_running_on = 0;
void hfp_call_setup_running_on_set(uint8_t set) { call_setup_running_on = set; }
void hfp_call_setup_running_on_clr(void) { call_setup_running_on = 0; }
uint8_t hfp_get_call_setup_running_on_state(void) {
TRACE(2, "%s state = %d", __func__, call_setup_running_on);
return call_setup_running_on;
}
static void hfp_connected_ind_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#ifdef __BT_ONE_BRING_TWO__
enum BT_DEVICE_ID_T anotherDevice =
(BT_DEVICE_ID_1 == chan_id_flag.id) ? BT_DEVICE_ID_2 : BT_DEVICE_ID_1;
#endif
#ifdef GFPS_ENABLED
app_exit_fastpairing_mode();
#endif
app_bt_clear_connecting_profiles_state(chan_id_flag.id);
TRACE(1, "::HF_EVENT_SERVICE_CONNECTED Chan_id:%d\n", chan_id_flag.id);
app_bt_device.phone_earphone_mark = 1;
#if defined(__BTIF_EARPHONE__)
if (ctx->state == BTIF_HF_STATE_OPEN) {
////report connected voice
app_bt_device.hf_conn_flag[chan_id_flag.id] = 1;
}
#endif
#if defined(SUPPORT_BATTERY_REPORT) || defined(SUPPORT_HF_INDICATORS)
uint8_t battery_level;
app_hfp_battery_report_reset(chan_id_flag.id);
app_battery_get_info(NULL, &battery_level, NULL);
app_hfp_set_battery_level(battery_level);
#endif
// app_bt_stream_hfpvolume_reset();
btif_hf_report_speaker_volume(chan, hfp_volume_get(chan_id_flag.id));
#if defined(HFP_DISABLE_NREC)
btif_hf_disable_nrec(chan);
#endif
#ifdef __BT_ONE_BRING_TWO__
////if a call is active and start bt open reconnect procedure, process the
/// curr_hf_channel_id
if ((app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_CON) ||
(app_bt_device.hfchan_callSetup[anotherDevice] ==
BTIF_HF_CALL_SETUP_IN)) {
app_bt_device.curr_hf_channel_id = anotherDevice;
} else {
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
}
#endif
#if defined(__BTMAP_ENABLE__) && defined(BTIF_DIP_DEVICE)
if ((btif_dip_get_process_status(app_bt_get_remoteDev(chan_id_flag.id))) &&
(app_btmap_check_is_idle(chan_id_flag.id))) {
app_btmap_sms_open(chan_id_flag.id, &ctx->remote_dev_bdaddr);
}
#endif
app_bt_profile_connect_manager_hf(chan_id_flag.id, chan, ctx);
#ifdef __INTERCONNECTION__
ask_is_selfdefined_battery_report_AT_command_support();
#endif
#ifdef __INTERACTION_CUSTOMER_AT_COMMAND__
Send_customer_phone_feature_support_AT_command(chan, 7);
Send_customer_battery_report_AT_command(chan, battery_level);
#endif
}
static void hfp_disconnected_ind_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
TRACE(2, "::HF_EVENT_SERVICE_DISCONNECTED Chan_id:%d, reason=%x\n",
chan_id_flag.id, ctx->disc_reason);
#if defined(HFP_1_6_ENABLE)
btif_hf_set_negotiated_codec(chan, BTIF_HF_SCO_CODEC_CVSD);
#endif
#if defined(__BTIF_EARPHONE__)
if (app_bt_device.hf_conn_flag[chan_id_flag.id]) {
////report device disconnected voice
app_bt_device.hf_conn_flag[chan_id_flag.id] = 0;
}
#endif
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP, BT_STREAM_VOICE,
chan_id_flag.id, MAX_RECORD_NUM);
for (uint8_t i = 0; i < BT_DEVICE_NUM; i++) {
if (chan == app_bt_device.hf_channel[i]) {
app_bt_device.hfchan_call[i] = 0;
app_bt_device.hfchan_callSetup[i] = 0;
app_bt_device.hf_audio_state[i] = BTIF_HF_AUDIO_DISCON;
app_bt_device.hf_conn_flag[i] = 0;
app_bt_device.hf_voice_en[i] = 0;
}
}
app_bt_profile_connect_manager_hf(chan_id_flag.id, chan, ctx);
}
static void hfp_audio_data_sent_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#if defined(SCO_LOOP)
hf_loop_buffer_valid = 1;
#endif
}
static void hfp_audio_data_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#ifdef __BT_ONE_BRING_TWO__
if (app_bt_device.hf_voice_en[chan_id_flag.id]) {
#endif
#ifndef _SCO_BTPCM_CHANNEL_
uint32_t idx = 0;
if (app_bt_stream_isrun(APP_BT_STREAM_HFP_PCM)) {
store_voicebtpcm_m2p_buffer(ctx->audio_data, ctx->audio_data_len);
idx = hf_sendbuff_ctrl.index % HF_SENDBUFF_MEMPOOL_NUM;
get_voicebtpcm_p2m_frame(&(hf_sendbuff_ctrl.mempool[idx].buffer[0]),
ctx->audio_data_len);
hf_sendbuff_ctrl.mempool[idx].packet.data =
&(hf_sendbuff_ctrl.mempool[idx].buffer[0]);
hf_sendbuff_ctrl.mempool[idx].packet.dataLen = ctx->audio_data_len;
hf_sendbuff_ctrl.mempool[idx].packet.flags = BTIF_BTP_FLAG_NONE;
if (!app_bt_device.hf_mute_flag) {
btif_hf_send_audio_data(chan, &hf_sendbuff_ctrl.mempool[idx].packet);
}
hf_sendbuff_ctrl.index++;
}
#endif
#ifdef __BT_ONE_BRING_TWO__
}
#endif
#if defined(SCO_LOOP)
memcpy(hf_loop_buffer + hf_loop_buffer_w_idx * HF_LOOP_SIZE,
Info->p.audioData->data, Info->p.audioData->len);
hf_loop_buffer_len[hf_loop_buffer_w_idx] = Info->p.audioData->len;
hf_loop_buffer_w_idx = (hf_loop_buffer_w_idx + 1) % HF_LOOP_CNT;
++hf_loop_buffer_size;
if (hf_loop_buffer_size >= 18 && hf_loop_buffer_valid == 1) {
hf_loop_buffer_valid = 0;
idx = hf_loop_buffer_w_idx - 17 < 0
? (HF_LOOP_CNT - (17 - hf_loop_buffer_w_idx))
: hf_loop_buffer_w_idx - 17;
pkt.flags = BTP_FLAG_NONE;
pkt.dataLen = hf_loop_buffer_len[idx];
pkt.data = hf_loop_buffer + idx * HF_LOOP_SIZE;
HF_SendAudioData(Chan, &pkt);
}
#endif
}
static void hfp_call_ind_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#ifdef __BT_ONE_BRING_TWO__
enum BT_DEVICE_ID_T anotherDevice =
(BT_DEVICE_ID_1 == chan_id_flag.id) ? BT_DEVICE_ID_2 : BT_DEVICE_ID_1;
#endif
#ifdef __BT_ONE_BRING_TWO__
TRACE(8,
"::HF_EVENT_CALL_IND %d chan_id %dx call %d %d held %d %d audio_state "
"%d %d\n",
ctx->call, chan_id_flag.id, app_bt_device.hfchan_call[BT_DEVICE_ID_1],
app_bt_device.hfchan_call[BT_DEVICE_ID_2],
app_bt_device.hf_callheld[BT_DEVICE_ID_1],
app_bt_device.hf_callheld[BT_DEVICE_ID_2],
app_bt_device.hf_audio_state[BT_DEVICE_ID_1],
app_bt_device.hf_audio_state[BT_DEVICE_ID_2]);
#else
TRACE(2, "::HF_EVENT_CALL_IND chan_id:%d, call:%d\n", chan_id_flag.id,
ctx->call);
#endif
if (ctx->call == BTIF_HF_CALL_NONE) {
hfp_call_setup_running_on_clr();
#if defined(_AUTO_TEST_)
AUTO_TEST_SEND("Call hangup ok.");
#endif
app_bt_device.hf_callheld[chan_id_flag.id] = BTIF_HF_CALL_HELD_NONE;
} else if (ctx->call == BTIF_HF_CALL_ACTIVE) {
#if defined(_AUTO_TEST_)
AUTO_TEST_SEND("Call setup ok.");
#endif
/// call is active so check if it's a outgoing call
if (app_bt_device.hfchan_callSetup[chan_id_flag.id] ==
BTIF_HF_CALL_SETUP_ALERT) {
TRACE(1, "HF CALLACTIVE TIME=%d", hal_sys_timer_get());
if (TICKS_TO_MS(hal_sys_timer_get() -
app_bt_device.hf_callsetup_time[chan_id_flag.id]) <
1000) {
TRACE(0, "DISABLE HANGUPCALL PROMPT");
app_bt_device.hf_endcall_dis[chan_id_flag.id] = true;
}
}
/////stop media of (ring and call number) and switch to sco
#if defined(HFP_NO_PRERMPT)
if (app_bt_device.hfchan_call[anotherDevice] == BTIF_HF_CALL_ACTIVE) {
} else
#endif
{
#ifdef __BT_ONE_BRING_TWO__
TRACE(1, "%s another %d,hf_callheld %d", __func__, anotherDevice,
app_bt_device.hf_callheld[anotherDevice]);
if ((btapp_hfp_get_call_state()) &&
(app_bt_device.hf_callheld[anotherDevice] == BTIF_HF_CALL_HELD_NONE))
#else
if (btapp_hfp_get_call_state())
#endif
{
TRACE(0, "DON'T SIWTCH_TO_SCO");
app_bt_device.hfchan_call[chan_id_flag.id] = ctx->call;
return;
} else {
#ifndef ENABLE_HFP_AUDIO_PENDING_FOR_MEDIA
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_SWITCHTO_SCO,
BT_STREAM_VOICE, chan_id_flag.id, 0);
#endif
}
}
} else {
#if defined(_AUTO_TEST_)
AUTO_TEST_SEND("Call hangup ok.");
#endif
}
#if defined(__BTIF_EARPHONE__)
hfp_app_status_indication(chan_id_flag.id, ctx);
#endif
if (ctx->call == BTIF_HF_CALL_ACTIVE) {
#if defined(HFP_NO_PRERMPT)
#else
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
#endif
}
#ifdef __BT_ONE_BRING_TWO__
else if ((ctx->call == BTIF_HF_CALL_NONE) &&
((app_bt_device.hfchan_call[anotherDevice] == BTIF_HF_CALL_ACTIVE) ||
(app_bt_device.hfchan_callSetup[anotherDevice] ==
BTIF_HF_CALL_SETUP_IN) ||
(app_bt_device.hfchan_callSetup[anotherDevice] ==
BTIF_HF_CALL_SETUP_OUT) ||
(app_bt_device.hfchan_callSetup[anotherDevice] ==
BTIF_HF_CALL_SETUP_ALERT))) {
app_bt_device.curr_hf_channel_id = anotherDevice;
}
#endif
TRACE(1, "!!!HF_EVENT_CALL_IND curr_hf_channel_id:%d\n",
app_bt_device.curr_hf_channel_id);
app_bt_device.hfchan_call[chan_id_flag.id] = ctx->call;
if (ctx->call == BTIF_HF_CALL_NONE) {
app_bt_device.hf_endcall_dis[chan_id_flag.id] = false;
}
#if defined(__BT_ONE_BRING_TWO__)
if (bt_get_sco_number() > 1
#ifdef CHIP_BEST1000
&& hal_get_chip_metal_id() >= HAL_CHIP_METAL_ID_2
#endif
) {
////a call is active:
if (app_bt_device.hfchan_call[chan_id_flag.id] == BTIF_HF_CALL_ACTIVE) {
#if !defined(HFP_NO_PRERMPT)
if (app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_CON) {
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
#ifdef __HF_KEEP_ONE_ALIVE__
#ifdef ENABLE_HFP_AUDIO_PENDING_FOR_MEDIA
if (bt_media_cur_is_bt_stream_media()) {
app_hfp_set_starting_media_pending_flag(true, chan_id_flag.id);
} else
#endif
{
app_hfp_start_voice_media(chan_id_flag.id);
}
#else
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_SWAP_SCO,
BT_STREAM_SBC, chan_id_flag.id, 0);
#endif
}
app_bt_device.hf_voice_en[chan_id_flag.id] = HF_VOICE_ENABLE;
app_bt_device.hf_voice_en[anotherDevice] = HF_VOICE_DISABLE;
#endif
} else {
////a call is hung up:
/// if one device setup a sco connect so get the other device's sco
/// state, if both connect mute the earlier one
if (app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_CON) {
app_bt_device.hf_voice_en[anotherDevice] = HF_VOICE_ENABLE;
app_bt_device.hf_voice_en[chan_id_flag.id] = HF_VOICE_DISABLE;
}
}
}
#endif
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_UPDATE_MEDIA,
BT_STREAM_VOICE, chan_id_flag.id,
MAX_RECORD_NUM);
}
extern uint8_t once_event_case;
extern void startonce_delay_event_Timer_(int ms);
extern void bt_drv_clear_skip_flag();
static void hfp_callsetup_ind_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#ifdef __BT_ONE_BRING_TWO__
// clear flag_skip_resv and flag_skip_retx
bt_drv_clear_skip_flag();
enum BT_DEVICE_ID_T anotherDevice =
(BT_DEVICE_ID_1 == chan_id_flag.id) ? BT_DEVICE_ID_2 : BT_DEVICE_ID_1;
#endif
TRACE(2, "::HF_EVENT_CALLSETUP_IND chan_id:%d, callSetup =%d\n",
chan_id_flag.id, ctx->call_setup);
if (ctx->call_setup == 0x03) {
once_event_case = 8;
startonce_delay_event_Timer_(1000);
}
if ((ctx->call_setup & 0x03) != 0) {
hfp_call_setup_running_on_set(1);
}
#if defined(__BTIF_EARPHONE__)
hfp_app_status_indication(chan_id_flag.id, ctx);
#endif
if (BTIF_HF_CALL_SETUP_NONE != ctx->call_setup) {
// exit sniff mode and stay active
app_bt_active_mode_set(ACTIVE_MODE_KEEPEER_SCO_STREAMING,
UPDATE_ACTIVE_MODE_FOR_ALL_LINKS);
} else {
// resume sniff mode
app_bt_active_mode_clear(ACTIVE_MODE_KEEPEER_SCO_STREAMING,
UPDATE_ACTIVE_MODE_FOR_ALL_LINKS);
}
#ifdef __BT_ONE_BRING_TWO__
TRACE(2, "call [0]/[1] =%d / %d", app_bt_device.hfchan_call[BT_DEVICE_ID_1],
app_bt_device.hfchan_call[BT_DEVICE_ID_2]);
TRACE(2, "audio [0]/[1] =%d / %d",
app_bt_device.hf_audio_state[BT_DEVICE_ID_1],
app_bt_device.hf_audio_state[BT_DEVICE_ID_2]);
app_bt_device.callSetupBitRec |= (1 << ctx->call_setup);
if (ctx->call_setup == 0) {
// do nothing
} else {
#ifdef BT_USB_AUDIO_DUAL_MODE
if (!btusb_is_bt_mode()) {
TRACE(0, "btusb_usbaudio_close doing.");
btusb_usbaudio_close();
}
#endif
#if defined(HFP_NO_PRERMPT)
if (((app_bt_device.hfchan_call[anotherDevice] == BTIF_HF_CALL_ACTIVE) &&
(app_bt_device.hfchan_call[chan_id_flag.id] == BTIF_HF_CALL_NONE)) ||
((app_bt_device.hfchan_callSetup[anotherDevice] ==
BTIF_HF_CALL_SETUP_IN) &&
(app_bt_device.hfchan_call[chan_id_flag.id] == BTIF_HF_CALL_NONE))) {
app_bt_device.curr_hf_channel_id = anotherDevice;
} else if ((app_bt_device.hfchan_call[chan_id_flag.id] ==
BTIF_HF_CALL_ACTIVE) &&
(app_bt_device.hfchan_call[anotherDevice] ==
BTIF_HF_CALL_ACTIVE)) {
} else {
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
}
#else
if ((app_bt_device.hfchan_call[anotherDevice] == BTIF_HF_CALL_ACTIVE) ||
((app_bt_device.hfchan_callSetup[anotherDevice] ==
BTIF_HF_CALL_SETUP_IN) &&
(app_bt_device.hfchan_call[chan_id_flag.id] != BTIF_HF_CALL_ACTIVE))) {
app_bt_device.curr_hf_channel_id = anotherDevice;
} else {
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
}
#endif
}
TRACE(1, "!!!HF_EVENT_CALLSETUP_IND curr_hf_channel_id:%d\n",
app_bt_device.curr_hf_channel_id);
#endif
app_bt_device.hfchan_callSetup[chan_id_flag.id] = ctx->call_setup;
/////call is alert so remember this time
if (app_bt_device.hfchan_callSetup[chan_id_flag.id] ==
BTIF_HF_CALL_SETUP_ALERT) {
TRACE(1, "HF CALLSETUP TIME=%d", hal_sys_timer_get());
app_bt_device.hf_callsetup_time[chan_id_flag.id] = hal_sys_timer_get();
}
if (app_bt_device.hfchan_callSetup[chan_id_flag.id] ==
BTIF_HF_CALL_SETUP_IN) {
btif_hf_list_current_calls(chan);
}
if ((app_bt_device.hfchan_callSetup[chan_id_flag.id] == 0) &&
(app_bt_device.hfchan_call[chan_id_flag.id] == 0)) {
hfp_call_setup_running_on_clr();
}
}
static void hfp_current_call_state_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
TRACE(1, "::HF_EVENT_CURRENT_CALL_STATE chan_id:%d\n", chan_id_flag.id);
#if defined(__BTIF_EARPHONE__)
hfp_app_status_indication(chan_id_flag.id, ctx);
#endif
}
void app_hfp_mute_upstream(uint8_t devId, bool isMute);
static void hfp_audio_connected_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#ifdef __BT_ONE_BRING_TWO__
enum BT_DEVICE_ID_T anotherDevice =
(BT_DEVICE_ID_1 == chan_id_flag.id) ? BT_DEVICE_ID_2 : BT_DEVICE_ID_1;
#endif
#if defined(HFP_1_6_ENABLE)
hf_chan_handle_t chan_tmp;
#endif
#ifdef __AI_VOICE__
ai_function_handle(CALLBACK_STOP_SPEECH, NULL, 0);
ai_function_handle(CALLBACK_AI_APP_KEEPALIVE_POST_HANDLER, NULL, 0); // check
#endif
if (ctx->status != BT_STS_SUCCESS)
return;
#if defined(IBRT)
app_ibrt_if_sniff_checker_start(APP_IBRT_IF_SNIFF_CHECKER_USER_HFP);
#endif
btdrv_set_powerctrl_rssi_low(0xffff);
btapp_hfp_mic_need_skip_frame_set(2);
#ifdef __BT_ONE_BRING_TWO__
#ifdef SUSPEND_ANOTHER_DEV_A2DP_STREAMING_WHEN_CALL_IS_COMING
if (app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_CON) {
TRACE(0, "::HF_EVENT_AUDIO_CONNECTED no need to update state");
return;
}
hfp_suspend_another_device_a2dp();
#endif
#endif
#ifdef __BT_ONE_BRING_TWO__
a2dp_dual_slave_setup_during_sco(chan_id_flag.id);
#endif
#if defined(HFP_1_6_ENABLE)
chan_tmp = app_bt_device.hf_channel[chan_id_flag.id];
uint16_t codec_id;
#if defined(IBRT)
ibrt_ctrl_t *p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx();
if (p_ibrt_ctrl->current_role == IBRT_SLAVE) {
codec_id = p_ibrt_ctrl->ibrt_sco_codec;
} else
#endif
{
codec_id = btif_hf_get_negotiated_codec(chan_tmp);
}
TRACE(2, "::HF_EVENT_AUDIO_CONNECTED chan_id:%d, codec_id:%d\n",
chan_id_flag.id, codec_id);
app_audio_manager_set_scocodecid(chan_id_flag.id, codec_id);
// bt_drv_reg_op_sco_txfifo_reset(codec_id);
#else
TRACE(1, "::HF_EVENT_AUDIO_CONNECTED chan_id:%d\n", chan_id_flag.id);
// bt_drv_reg_op_sco_txfifo_reset(1);
#endif
#if defined(HFP_NO_PRERMPT)
if (((app_bt_device.hfchan_call[anotherDevice] == BTIF_HF_CALL_ACTIVE) &&
(app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_DISCON)) &&
((app_bt_device.hf_audio_state[chan_id_flag.id] ==
BTIF_HF_AUDIO_DISCON) &&
(app_bt_device.hfchan_call[chan_id_flag.id] == BTIF_HF_CALL_ACTIVE))) {
app_bt_device.phone_earphone_mark = 0;
app_bt_device.hf_mute_flag = 0;
} else if ((app_bt_device.hf_audio_state[chan_id_flag.id] ==
BTIF_HF_AUDIO_CON) ||
(app_bt_device.hf_audio_state[anotherDevice] ==
BTIF_HF_AUDIO_CON)) {
} else
#endif
{
app_bt_device.phone_earphone_mark = 0;
app_bt_device.hf_mute_flag = 0;
}
app_bt_device.hf_audio_state[chan_id_flag.id] = BTIF_HF_AUDIO_CON;
#if defined(__FORCE_REPORTVOLUME_SOCON__)
btif_hf_report_speaker_volume(chan, hfp_volume_get(chan_id_flag.id));
#endif
#ifdef __BT_ONE_BRING_TWO__
if (bt_get_sco_number() > 1
#ifdef CHIP_BEST1000
&& hal_get_chip_metal_id() >= HAL_CHIP_METAL_ID_2
#endif
) {
if (app_bt_device.hfchan_call[chan_id_flag.id] == BTIF_HF_CALL_ACTIVE) {
#if !defined(HFP_NO_PRERMPT)
#ifndef __HF_KEEP_ONE_ALIVE__
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_SWAP_SCO,
BT_STREAM_SBC, chan_id_flag.id, 0);
#endif
app_bt_device.hf_voice_en[chan_id_flag.id] = HF_VOICE_ENABLE;
app_bt_device.hf_voice_en[anotherDevice] = HF_VOICE_DISABLE;
#else
if ((app_bt_device.hfchan_call[anotherDevice] == BTIF_HF_CALL_NONE) &&
(app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_DISCON))
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
#ifdef _THREE_WAY_ONE_CALL_COUNT__
app_hfp_set_cur_chnl_id(chan_id_flag.id);
TRACE(4, "%s :%d : app_bt_device.hf_callheld[%d]: %d\n", __func__,
__LINE__, chan_id_flag.id,
app_bt_device.hf_callheld[chan_id_flag.id]);
if (app_bt_device.hf_callheld[chan_id_flag.id] ==
BTIF_HF_CALL_HELD_ACTIVE) {
if (app_hfp_get_cur_call_chnl(NULL) == chan_id_flag.id)
app_hfp_3_way_call_counter_set(chan_id_flag.id, 1);
} else if ((app_bt_device.hf_callheld[chan_id_flag.id] ==
BTIF_HF_CALL_HELD_NONE) ||
(app_bt_device.hf_callheld[chan_id_flag.id] ==
BTIF_HF_CALL_HELD_NO_ACTIVE)) {
if (app_hfp_get_cur_call_chnl(NULL) == chan_id_flag.id)
app_hfp_3_way_call_counter_set(chan_id_flag.id, 0);
}
#endif
#endif
} else if (app_bt_device.hf_audio_state[anotherDevice] ==
BTIF_HF_AUDIO_CON) {
app_bt_device.hf_voice_en[chan_id_flag.id] = HF_VOICE_DISABLE;
app_bt_device.hf_voice_en[anotherDevice] = HF_VOICE_ENABLE;
}
} else {
/// if one device setup a sco connect so get the other device's sco state,
/// if both connect mute the earlier one
if (app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_CON) {
app_bt_device.hf_voice_en[anotherDevice] = HF_VOICE_DISABLE;
}
app_bt_device.hf_voice_en[chan_id_flag.id] = HF_VOICE_ENABLE;
}
#ifndef __HF_KEEP_ONE_ALIVE__
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START, BT_STREAM_VOICE,
chan_id_flag.id, MAX_RECORD_NUM);
#endif
#if defined(HFP_NO_PRERMPT)
TRACE(2, "call[id_other] =%d audio[id_other] = %d",
app_bt_device.hfchan_call[anotherDevice],
app_bt_device.hf_audio_state[anotherDevice]);
if (/*(app_bt_device.hfchan_call[anotherDevice] == HF_CALL_ACTIVE)&&*/
(app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_CON)) {
} else
#endif
{
if (bt_media_cur_is_bt_stream_media()) {
app_hfp_start_voice_media(chan_id_flag.id);
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
} else {
#ifdef __BT_ONE_BRING_TWO__
TRACE(1, "%s another[%d] hf_audio_state %d,", __func__, anotherDevice,
app_bt_device.hf_audio_state[anotherDevice]);
if (BTIF_HF_AUDIO_CON == app_bt_device.hf_audio_state[anotherDevice]) {
TRACE(1,
"disconnect current audio link and don't swith to current sco");
btif_hf_disc_audio_link(app_bt_device.hf_channel[chan_id_flag.id]);
app_bt_device.curr_hf_channel_id = anotherDevice;
}
#else
if (bt_is_sco_media_open()) {
TRACE(0,
"disconnect current audio link and don't swith to current sco");
app_bt_HF_DisconnectAudioLink(
app_bt_device.hf_channel[chan_id_flag.id]);
}
#endif
else {
app_hfp_start_voice_media(chan_id_flag.id);
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
}
}
}
#else
#ifdef _THREE_WAY_ONE_CALL_COUNT__
app_hfp_set_cur_chnl_id(chan_id_flag.id);
#endif
#ifdef ENABLE_HFP_AUDIO_PENDING_FOR_MEDIA
if (bt_media_cur_is_bt_stream_media()) {
app_hfp_set_starting_media_pending_flag(true, BT_DEVICE_ID_1);
} else
#endif
{
app_hfp_start_voice_media(BT_DEVICE_ID_1);
}
#endif
#ifdef __IAG_BLE_INCLUDE__
app_ble_update_conn_param_mode(BLE_CONN_PARAM_MODE_HFP_ON, true);
#endif
}
static void hfp_audio_disconnected_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#ifdef __BT_ONE_BRING_TWO__
// clear flag_skip_resv and flag_skip_retx
bt_drv_clear_skip_flag();
enum BT_DEVICE_ID_T anotherDevice =
(BT_DEVICE_ID_1 == chan_id_flag.id) ? BT_DEVICE_ID_2 : BT_DEVICE_ID_1;
#endif
#ifdef BT_USB_AUDIO_DUAL_MODE
if (!btusb_is_bt_mode()) {
TRACE(0, "btusb_usbaudio_open doing.");
btusb_usbaudio_open();
}
#endif
app_hfp_set_starting_media_pending_flag(false, 0);
#if defined(IBRT)
app_ibrt_if_sniff_checker_stop(APP_IBRT_IF_SNIFF_CHECKER_USER_HFP);
#endif
#ifdef __BT_ONE_BRING_TWO__
#ifdef SUSPEND_ANOTHER_DEV_A2DP_STREAMING_WHEN_CALL_IS_COMING
if (app_bt_is_to_resume_music_player(anotherDevice)) {
app_bt_resume_music_player(anotherDevice);
}
#endif
#endif
#ifdef __BT_ONE_BRING_TWO__
a2dp_dual_slave_handling_refresh();
#endif
TRACE(1, "::HF_EVENT_AUDIO_DISCONNECTED chan_id:%d\n", chan_id_flag.id);
if (app_bt_device.hfchan_call[chan_id_flag.id] == BTIF_HF_CALL_ACTIVE) {
app_bt_device.phone_earphone_mark = 1;
}
app_bt_device.hf_audio_state[chan_id_flag.id] = BTIF_HF_AUDIO_DISCON;
/* Dont clear callsetup status when audio disc: press iphone volume button
will disc audio link, but the iphone incoming call is still exist. The
callsetup status will be reported after call rejected or answered. */
// app_bt_device.hfchan_callSetup[chan_id_flag.id] = BTIF_HF_CALL_SETUP_NONE;
#ifdef __IAG_BLE_INCLUDE__
if (!app_bt_is_in_reconnecting()) {
app_hfp_resume_ble_adv();
}
app_ble_update_conn_param_mode(BLE_CONN_PARAM_MODE_HFP_ON, false);
#endif
#if defined(CHIP_BEST2300P) || defined(CHIP_BEST2300A) || \
defined(CHIP_BEST1400) || defined(CHIP_BEST1402)
bt_drv_reg_op_clean_flags_of_ble_and_sco();
#endif
#ifdef __BT_ONE_BRING_TWO__
if (btif_get_hf_chan_state(app_bt_device.hf_channel[anotherDevice]) !=
BTIF_HF_STATE_OPEN) {
TRACE(2, "!!!HF_EVENT_AUDIO_DISCONNECTED hfchan_call[%d]:%d\n",
anotherDevice, app_bt_device.hfchan_call[anotherDevice]);
}
if ((app_bt_device.hfchan_call[anotherDevice] == BTIF_HF_CALL_ACTIVE) ||
(app_bt_device.hfchan_callSetup[anotherDevice] ==
BTIF_HF_CALL_SETUP_IN)) {
// app_bt_device.curr_hf_channel_id = chan_id_flag.id_other;
TRACE(
1,
"!!!HF_EVENT_AUDIO_DISCONNECTED app_bt_device.curr_hf_channel_id:%d\n",
app_bt_device.curr_hf_channel_id);
} else {
app_bt_device.curr_hf_channel_id = chan_id_flag.id;
}
#if defined(_THREE_WAY_ONE_CALL_COUNT__)
if (chan_id_flag.id == app_hfp_get_cur_call_chnl(NULL)) {
app_hfp_cur_call_chnl_reset(chan_id_flag.id);
}
#endif
app_bt_device.hf_voice_en[chan_id_flag.id] = HF_VOICE_DISABLE;
if (app_bt_device.hf_audio_state[anotherDevice] == BTIF_HF_AUDIO_CON) {
app_bt_device.hf_voice_en[anotherDevice] = HF_VOICE_ENABLE;
TRACE(1, "chan_id:%d AUDIO_DISCONNECTED, then enable id_other voice",
chan_id_flag.id);
}
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP, BT_STREAM_VOICE,
chan_id_flag.id, MAX_RECORD_NUM);
#else
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP, BT_STREAM_VOICE,
BT_DEVICE_ID_1, MAX_RECORD_NUM);
#endif
app_bt_device.callSetupBitRec = 0;
// app_hfp_mute_upstream(chan_id_flag.id, true);
#if defined(HFP_1_6_ENABLE)
uint16_t codec_id =
btif_hf_get_negotiated_codec(app_bt_device.hf_channel[chan_id_flag.id]);
bt_drv_reg_op_sco_txfifo_reset(codec_id);
#else
bt_drv_reg_op_sco_txfifo_reset(1);
#endif
app_bt_active_mode_clear(ACTIVE_MODE_KEEPEER_SCO_STREAMING,
UPDATE_ACTIVE_MODE_FOR_ALL_LINKS);
}
static void hfp_ring_ind_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#if defined(__BTIF_EARPHONE__) && defined(MEDIA_PLAYER_SUPPORT)
#ifdef __BT_ONE_BRING_TWO__
enum BT_DEVICE_ID_T anotherDevice =
(BT_DEVICE_ID_1 == chan_id_flag.id) ? BT_DEVICE_ID_2 : BT_DEVICE_ID_1;
#endif
TRACE(1, "::HF_EVENT_RING_IND chan_id:%d\n", chan_id_flag.id);
TRACE(1, "btif_hf_is_inbandring_enabled:%d",
btif_hf_is_inbandring_enabled(chan));
#if defined(__BT_ONE_BRING_TWO__)
if ((app_bt_device.hf_audio_state[chan_id_flag.id] != BTIF_HF_AUDIO_CON) &&
(app_bt_device.hf_audio_state[anotherDevice] != BTIF_HF_AUDIO_CON))
app_voice_report(APP_STATUS_INDICATION_INCOMINGCALL, chan_id_flag.id);
#else
#if defined(IBRT)
ibrt_ctrl_t *p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx();
if (p_ibrt_ctrl->current_role == IBRT_SLAVE)
return;
#endif
if (app_bt_device.hf_audio_state[chan_id_flag.id] != BTIF_HF_AUDIO_CON)
app_voice_report(APP_STATUS_INDICATION_INCOMINGCALL, chan_id_flag.id);
#endif
#endif
}
static void hfp_speak_volume_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
TRACE(2, "::HF_EVENT_SPEAKER_VOLUME chan_id:%d,speaker gain = %d\n",
chan_id_flag.id, ctx->speaker_volume);
hfp_volume_set(chan_id_flag.id, (int)ctx->speaker_volume);
}
static void hfp_voice_rec_state_ind_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
TRACE(2, "::HF_EVENT_VOICE_REC_STATE chan_id:%d,voice_rec_state = %d\n",
chan_id_flag.id, ctx->voice_rec_state);
}
static void hfp_bes_test_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
// TRACE(0,"HF_EVENT_BES_TEST content =d", Info->p.ptr);
}
static void hfp_read_ag_ind_status_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
TRACE(1, "HF_EVENT_READ_AG_INDICATORS_STATUS %s\n", __func__);
}
static void hfp_call_held_ind_handler(hf_chan_handle_t chan,
struct hfp_context *ctx) {
#if defined(__BT_ONE_BRING_TWO__)
TRACE(8,
"::HF_EVENT_CALLHELD_IND %d chan_id %d call %d %d held %d %d "
"audio_state %d %d\n",
ctx->call_held, chan_id_flag.id,
app_bt_device.hfchan_call[BT_DEVICE_ID_1],
app_bt_device.hfchan_call[BT_DEVICE_ID_2],
app_bt_device.hf_callheld[BT_DEVICE_ID_1],
app_bt_device.hf_callheld[BT_DEVICE_ID_2],
app_bt_device.hf_audio_state[BT_DEVICE_ID_1],
app_bt_device.hf_audio_state[BT_DEVICE_ID_2]);
#else
TRACE(2, "::HF_EVENT_CALLHELD_IND chan_id:%d HELD_STATUS = %d \n",
chan_id_flag.id, ctx->call_held);
#endif
#if defined(_THREE_WAY_ONE_CALL_COUNT__)
#if defined(__BT_ONE_BRING_TWO__)
if (app_bt_device.hf_audio_state[chan_id_flag.id] == BTIF_HF_AUDIO_CON &&
(ctx->call_held == BTIF_HF_CALL_HELD_NONE ||
ctx->call_held == BTIF_HF_CALL_HELD_ACTIVE)) {
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_SWITCHTO_SCO,
BT_STREAM_VOICE, chan_id_flag.id, 0);
}
#endif
app_bt_device.hf_callheld[chan_id_flag.id] = ctx->call_held;
if (ctx->call_held == BTIF_HF_CALL_HELD_ACTIVE) {
if (app_hfp_get_cur_call_chnl(NULL) == chan_id_flag.id)
app_hfp_3_way_call_counter_set(chan_id_flag.id, 1);
} else if ((ctx->call_held == BTIF_HF_CALL_HELD_NONE) ||
(ctx->call_held == BTIF_HF_CALL_HELD_NO_ACTIVE)) {
if (app_hfp_get_cur_call_chnl(NULL) == chan_id_flag.id)
app_hfp_3_way_call_counter_set(chan_id_flag.id, 0);
} else {
TRACE(0, "UNKNOWN CMD.IGNORE");
}
#endif
}
static uint8_t skip_frame_cnt = 0;
void app_hfp_set_skip_frame(uint8_t frames) { skip_frame_cnt = frames; }
uint8_t app_hfp_run_skip_frame(void) {
if (skip_frame_cnt > 0) {
skip_frame_cnt--;
return 1;
}
return 0;
}
uint8_t hfp_is_service_connected(uint8_t device_id) {
if (device_id >= BT_DEVICE_NUM)
return 0;
return app_bt_device.hf_conn_flag[device_id];
}
#if HF_VERSION_1_6 == XA_ENABLED
// HfCommand hf_codec_sel_command;
#endif
static uint8_t app_hfp_is_starting_media_pending_flag = false;
static uint8_t app_hfp_pending_dev_id;
bool app_hfp_is_starting_media_pending(void) {
return app_hfp_is_starting_media_pending_flag;
}
static uint8_t upstreamMute = 0xff;
void app_hfp_mute_upstream(uint8_t devId, bool isMute) {
if (upstreamMute != isMute) {
TRACE(3, "%s devId %d isMute %d", __func__, devId, isMute);
upstreamMute = isMute;
if (isMute) {
btdrv_set_bt_pcm_en(0);
} else {
btdrv_set_bt_pcm_en(1);
}
}
}
static void app_hfp_set_starting_media_pending_flag(bool isEnabled,
uint8_t devId) {
TRACE(1, "%s %d.Current state %d toEnable %d", __func__, __LINE__,
app_hfp_is_starting_media_pending_flag, isEnabled);
if ((app_hfp_is_starting_media_pending_flag && isEnabled) ||
(!app_hfp_is_starting_media_pending_flag && !isEnabled)) {
return;
}
app_hfp_is_starting_media_pending_flag = isEnabled;
app_hfp_pending_dev_id = devId;
#if 0
if (isEnabled)
{
if (!app_hfp_mediaplay_delay_resume_timer_id ) {
app_hfp_mediaplay_delay_resume_timer_id =
osTimerCreate(osTimer(APP_HFP_MEDIAPLAY_DELAY_RESUME_TIMER),
osTimerOnce, NULL);
}
osTimerStart(app_hfp_mediaplay_delay_resume_timer_id ,
HFP_MEDIAPLAY_DELAY_RESUME_IN_MS);
}
#endif
}
void app_hfp_start_voice_media(uint8_t devId) {
app_hfp_set_starting_media_pending_flag(false, 0);
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START, BT_STREAM_VOICE,
devId, MAX_RECORD_NUM);
}
void app_hfp_resume_pending_voice_media(void) {
if (btapp_hfp_is_dev_sco_connected(app_hfp_pending_dev_id)) {
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START, BT_STREAM_VOICE,
app_hfp_pending_dev_id, MAX_RECORD_NUM);
app_hfp_set_starting_media_pending_flag(false, 0);
}
}
#include "app_bt_func.h"
void hfp_multipoint_audio_manage_a2dp_callback() {
#ifdef SUSPEND_ANOTHER_DEV_A2DP_STREAMING_WHEN_CALL_IS_COMING
int i = 0;
int j = 0;
TRACE(1, "%s", __func__);
for (i = 0; i < BT_DEVICE_NUM; i++) {
if (app_bt_device.a2dp_streamming[i] == 1)
break;
}
if (i == BT_DEVICE_NUM)
return;
for (j = 0; j < BT_DEVICE_NUM; j++) {
if (app_bt_device.hf_audio_state[j] == BTIF_HF_AUDIO_CON)
break;
}
if (j == BT_DEVICE_NUM)
return;
btif_remote_device_t *activeA2dpRem =
A2DP_GetRemoteDevice(app_bt_device.a2dp_connected_stream[i]);
btif_remote_device_t *activeHfpRem =
(btif_remote_device_t *)btif_hf_cmgr_get_remote_device(
app_bt_device.hf_channel[j]);
if (activeA2dpRem == activeHfpRem)
return;
TRACE(0, "different profile device");
if (app_bt_is_music_player_working(i)) {
bool isPaused = app_bt_pause_music_player(i);
if (isPaused) {
app_bt_set_music_player_resume_device(i);
}
} else if (app_bt_is_a2dp_streaming(i)) {
app_bt_suspend_a2dp_streaming(i);
}
#endif
}
void hfp_suspend_another_device_a2dp(void) {
app_bt_start_custom_function_in_bt_thread(
0, 0, (uint32_t)hfp_multipoint_audio_manage_a2dp_callback);
}
static void app_hfp_audio_closed_delay_resume_ble_adv_timer_cb(void const *n) {
#ifdef __IAG_BLE_INCLUDE__
app_ble_refresh_adv_state(BLE_ADVERTISING_INTERVAL);
#endif
}
#ifdef __IAG_BLE_INCLUDE__
static void app_hfp_resume_ble_adv(void) {
if (!app_hfp_audio_closed_delay_resume_ble_adv_timer_id) {
app_hfp_audio_closed_delay_resume_ble_adv_timer_id =
osTimerCreate(osTimer(APP_HFP_AUDIO_CLOSED_DELAY_RESUME_BLE_ADV_TIMER),
osTimerOnce, NULL);
}
osTimerStart(app_hfp_audio_closed_delay_resume_ble_adv_timer_id,
HFP_AUDIO_CLOSED_DELAY_RESUME_ADV_IN_MS);
}
#endif
#ifdef __BT_ONE_BRING_TWO__
#if defined(__BT_SELECT_PROF_DEVICE_ID__)
static void _app_hfp_select_channel(hf_chan_handle_t chan,
struct hfp_context *ctx) {
uint32_t i = 0;
btif_remote_device_t *matching_remdev = NULL, *wanted_remdev = NULL;
hf_chan_handle_t curr_channel;
wanted_remdev = ctx->chan_sel_remDev;
// default channel is NULL
*(ctx->chan_sel_channel) = NULL;
for (i = 0; i < BT_DEVICE_NUM; i++) {
// Other profile connected
curr_channel = app_bt_device.hf_channel[i];
if (app_bt_is_any_profile_connected(i)) {
matching_remdev = app_bt_get_connected_profile_remdev(i);
TRACE(3, "device_id=%d, hfp_select_channel : remdev=0x%x:0x%x.", i,
wanted_remdev, matching_remdev);
TRACE(1, "device_id=%d, hfp_select_channel : other_profile_connected.",
i);
if (wanted_remdev == matching_remdev) {
TRACE(2, "device_id=%d, hfp_select_channel : found_same_remdev : 0x%x",
i, &(app_bt_device.hf_channel[i]));
if (btif_get_hf_chan_state(curr_channel) == BTIF_HF_STATE_CLOSED) {
TRACE(1,
"device_id=%d, hfp_select_channel : current_channel_is_closed, "
"good.",
i);
*(ctx->chan_sel_channel) = (uint32_t *)curr_channel;
} else {
TRACE(2,
"device_id=%d, hfp_select_channel : other_profile_connected: "
"current_channel_is_not_closed %d, ohno.",
i, btif_get_hf_chan_state(curr_channel));
TRACE(1,
"device_id=%d, hfp_select_channel : other_profile_connected: "
"missed right channel, found nothing, return",
i);
}
return;
} else {
TRACE(1,
"device_id=%d, hfp_select_channel : different_remdev, see next "
"device id",
i);
}
} else {
TRACE(1,
"device_id=%d, hfp_select_channel : other_profile_not_connected.",
i);
// first found idle device id is min device id we want
// Assume : other profile will use device id ascending
// TODO to keep other profile use device id ascending
if (btif_get_hf_chan_state(curr_channel) == BTIF_HF_STATE_CLOSED) {
TRACE(1,
"device_id=%d, hfp_select_channel : current_channel_is_closed, "
"choose this idle channel.",
i);
*(ctx->chan_sel_channel) = (uint32_t *)curr_channel;
} else {
TRACE(2,
"device_id=%d, hfp_select_channel : no_other_profile_connected : "
"current_channel_is_not_closed %d, ohno.",
i, btif_get_hf_chan_state(curr_channel));
TRACE(1,
"device_id=%d, hfp_select_channel : no_other_profile_connected : "
"missed right channel, found nothing, return",
i);
}
return;
}
}
}
#endif
#endif
void app_hfp_event_callback(hf_chan_handle_t chan, struct hfp_context *ctx) {
struct bt_cb_tag *bt_drv_func_cb = bt_drv_get_func_cb_ptr();
#ifdef __BT_ONE_BRING_TWO__
if (ctx->event == BTIF_HF_EVENT_SELECT_CHANNEL) {
#if defined(__BT_SELECT_PROF_DEVICE_ID__)
_app_hfp_select_channel(chan, ctx);
#endif
return;
}
hfp_chan_id_distinguish(chan);
#else
if (ctx->event == BTIF_HF_EVENT_SELECT_CHANNEL) {
return;
}
chan_id_flag.id = BT_DEVICE_ID_1;
#endif
switch (ctx->event) {
case BTIF_HF_EVENT_SERVICE_CONNECTED:
hfp_connected_ind_handler(chan, ctx);
break;
case BTIF_HF_EVENT_AUDIO_DATA_SENT:
hfp_audio_data_sent_handler(chan, ctx);
break;
case BTIF_HF_EVENT_AUDIO_DATA:
hfp_audio_data_handler(chan, ctx);
break;
case BTIF_HF_EVENT_SERVICE_DISCONNECTED:
hfp_disconnected_ind_handler(chan, ctx);
break;
case BTIF_HF_EVENT_CALL_IND:
hfp_call_ind_handler(chan, ctx);
break;
case BTIF_HF_EVENT_CALLSETUP_IND:
hfp_callsetup_ind_handler(chan, ctx);
break;
case BTIF_HF_EVENT_CURRENT_CALL_STATE:
hfp_current_call_state_handler(chan, ctx);
break;
case BTIF_HF_EVENT_AUDIO_CONNECTED:
#ifdef IBRT
{
ibrt_ctrl_t *p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx();
bt_drv_reg_op_set_agc_thd(p_ibrt_ctrl->current_role == IBRT_MASTER, true);
if (!btif_besaud_is_connected()) {
bt_drv_reg_op_hack_max_slot(p_ibrt_ctrl->mobile_conhandle - 0x80, 1);
}
}
#endif
if (bt_drv_func_cb->bt_switch_agc != NULL) {
bt_drv_func_cb->bt_switch_agc(BT_HFP_WORK_MODE);
}
hfp_audio_connected_handler(chan, ctx);
break;
case BTIF_HF_EVENT_AUDIO_DISCONNECTED:
if (bt_drv_func_cb->bt_switch_agc != NULL) {
bt_drv_func_cb->bt_switch_agc(BT_IDLE_MODE);
}
hfp_audio_disconnected_handler(chan, ctx);
break;
case BTIF_HF_EVENT_RING_IND:
hfp_ring_ind_handler(chan, ctx);
break;
case BTIF_HF_EVENT_SPEAKER_VOLUME:
hfp_speak_volume_handler(chan, ctx);
break;
#ifdef SUPPORT_SIRI
case BTIF_HF_EVENT_SIRI_STATUS:
break;
#endif
case BTIF_HF_EVENT_BES_TEST:
hfp_bes_test_handler(chan, ctx);
break;
case BTIF_HF_EVENT_READ_AG_INDICATORS_STATUS:
hfp_read_ag_ind_status_handler(chan, ctx);
break;
case BTIF_HF_EVENT_CALLHELD_IND:
hfp_call_held_ind_handler(chan, ctx);
break;
case BTIF_HF_EVENT_COMMAND_COMPLETE:
break;
case BTIF_HF_EVENT_AT_RESULT_DATA:
TRACE(1, "received AT command: %s", ctx->ptr);
#ifdef __INTERACTION__
if (!memcmp(oppo_self_defined_command_response, ctx->ptr,
strlen(oppo_self_defined_command_response))) {
for (int i = 0; i < BT_DEVICE_NUM; i++) {
chan = app_bt_device.hf_channel[i];
{
TRACE(2, "hf state=%x %d", chan, btif_get_hf_chan_state(chan));
if (btif_get_hf_chan_state(chan) == BTIF_HF_STATE_OPEN) {
// char firmwareversion[] = "AT+VDRV=3,1,9,2,9,3,9";
// sprintf(&firmwareversion[27], "%d", (int)NeonFwVersion[0]);
// sprintf(&firmwareversion[28], "%d", (int)NeonFwVersion[1]);
// sprintf(&firmwareversion[29], "%d", (int)NeonFwVersion[2]);
// btif_hf_send_at_cmd(chan,firmwareversion);
}
}
}
TRACE(0, "oppo_self_defined_command_response");
}
#endif
#ifdef __INTERCONNECTION__
if (!memcmp(huawei_self_defined_command_response, ctx->ptr,
strlen(huawei_self_defined_command_response) + 1)) {
uint8_t *pSelfDefinedCommandSupport =
app_battery_get_mobile_support_self_defined_command_p();
*pSelfDefinedCommandSupport = 1;
TRACE(0, "send self defined AT command to mobile.");
send_selfdefined_battery_report_AT_command();
}
#endif
break;
case BTIF_HF_EVENT_VOICE_REC_STATE:
hfp_voice_rec_state_ind_handler(chan, ctx);
break;
default:
break;
}
#ifdef __BT_ONE_BRING_TWO__
hfcall_next_sta_handler(ctx->event);
#endif
#if defined(IBRT)
app_tws_ibrt_profile_callback(BTIF_APP_HFP_PROFILE_ID, (void *)chan,
(void *)ctx);
#endif
}
uint8_t btapp_hfp_get_call_state(void) {
uint8_t i;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if (app_bt_device.hfchan_call[i] == BTIF_HF_CALL_ACTIVE) {
return 1;
}
}
return 0;
}
uint8_t btapp_hfp_get_call_setup(void) {
uint8_t i;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if ((app_bt_device.hfchan_callSetup[i] != BTIF_HF_CALL_SETUP_NONE)) {
return (app_bt_device.hfchan_callSetup[i]);
}
}
return 0;
}
uint8_t btapp_hfp_incoming_calls(void) {
uint8_t i;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if (app_bt_device.hfchan_callSetup[i] == BTIF_HF_CALL_SETUP_IN) {
return 1;
}
}
return 0;
}
bool btapp_hfp_is_call_active(void) {
uint8_t i;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if ((app_bt_device.hfchan_call[i] == BTIF_HF_CALL_ACTIVE) &&
(app_bt_device.hf_audio_state[i] == BTIF_HF_AUDIO_CON)) {
return true;
}
}
return false;
}
bool btapp_hfp_is_sco_active(void) {
uint8_t i;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if (app_bt_device.hf_audio_state[i] == BTIF_HF_AUDIO_CON) {
return true;
}
}
return false;
}
bool btapp_hfp_is_dev_call_active(uint8_t devId) {
return ((app_bt_device.hfchan_call[devId] == BTIF_HF_CALL_ACTIVE) &&
(app_bt_device.hf_audio_state[devId] == BTIF_HF_AUDIO_CON));
}
bool btapp_hfp_is_dev_sco_connected(uint8_t devId) {
return (app_bt_device.hf_audio_state[devId] == BTIF_HF_AUDIO_CON);
}
uint8_t btapp_hfp_get_call_active(void) {
uint8_t i;
for (i = 0; i < BT_DEVICE_NUM; i++) {
if ((app_bt_device.hfchan_call[i] == BTIF_HF_CALL_ACTIVE) ||
(app_bt_device.hfchan_callSetup[i] == BTIF_HF_CALL_SETUP_ALERT)) {
return 1;
}
}
return 0;
}
void btapp_hfp_report_speak_gain(void) {
uint8_t i;
btif_remote_device_t *remDev = NULL;
btif_link_mode_t mode = BTIF_BLM_SNIFF_MODE;
hf_chan_handle_t chan;
for (i = 0; i < BT_DEVICE_NUM; i++) {
osapi_lock_stack();
remDev = (btif_remote_device_t *)btif_hf_cmgr_get_remote_device(
app_bt_device.hf_channel[i]);
if (remDev) {
mode = btif_me_get_current_mode(remDev);
} else {
mode = BTIF_BLM_SNIFF_MODE;
}
chan = app_bt_device.hf_channel[i];
if ((btif_get_hf_chan_state(chan) == BTIF_HF_STATE_OPEN) &&
(mode == BTIF_BLM_ACTIVE_MODE)) {
btif_hf_report_speaker_volume(chan,
hfp_volume_get((enum BT_DEVICE_ID_T)i));
}
osapi_unlock_stack();
}
}
uint8_t btapp_hfp_need_mute(void) { return app_bt_device.hf_mute_flag; }
int32_t hfp_mic_need_skip_frame_cnt = 0;
bool btapp_hfp_mic_need_skip_frame(void) {
bool nRet;
if (hfp_mic_need_skip_frame_cnt > 0) {
hfp_mic_need_skip_frame_cnt--;
nRet = true;
} else {
app_hfp_mute_upstream(0, false);
nRet = false;
}
return nRet;
}
void btapp_hfp_mic_need_skip_frame_set(int32_t skip_frame) {
hfp_mic_need_skip_frame_cnt = skip_frame;
}
#if defined(CHIP_BEST2300) || defined(CHIP_BEST2300P) || defined(CHIP_BEST2300A)
typedef void (*btapp_set_sco_switch_cmd_callback)(void);
btapp_set_sco_switch_cmd_callback set_sco_switch_cmd_callback;
void btapp_sco_switch_set_pcm(void) {
TRACE(0, "btapp_sco_switch_set_pcm\n");
TRACE(1, "0xd02201b0 = 0x%x before\n", *(volatile uint32_t *)(0xd02201b0));
osDelay(20);
btdrv_pcm_enable();
TRACE(1, "0xd02201b0 = 0x%x after\n", *(volatile uint32_t *)(0xd02201b0));
}
#endif
void app_hfp_init(void) {
hfp_hfcommand_mempool_init();
#if defined(ENHANCED_STACK)
btif_hfp_initialize();
#endif /* ENHANCED_STACK */
app_bt_device.curr_hf_channel_id = BT_DEVICE_ID_1;
app_bt_device.hf_mute_flag = 0;
for (uint8_t i = 0; i < BT_DEVICE_NUM; i++) {
app_bt_device.hf_channel[i] = btif_hf_create_channel();
if (!app_bt_device.hf_channel[i]) {
ASSERT(0, "Serious error: cannot create hf channel\n");
}
btif_hf_init_channel(app_bt_device.hf_channel[i]);
app_bt_device.hfchan_call[i] = 0;
app_bt_device.hfchan_callSetup[i] = 0;
app_bt_device.hf_audio_state[i] = BTIF_HF_AUDIO_DISCON,
app_bt_device.hf_conn_flag[i] = false;
app_bt_device.hf_voice_en[i] = 0;
}
btif_hf_register_callback(app_hfp_event_callback);
#if defined(SUPPORT_BATTERY_REPORT) || defined(SUPPORT_HF_INDICATORS)
Besbt_hook_handler_set(BESBT_HOOK_USER_3, app_hfp_battery_report_proc);
#endif
#if defined(CHIP_BEST2300) || defined(CHIP_BEST2300P) || defined(CHIP_BEST2300A)
set_sco_switch_cmd_callback = btapp_sco_switch_set_pcm;
#endif
app_hfp_mute_upstream(chan_id_flag.id, true);
}
void app_hfp_enable_audio_link(bool isEnable) { return; }
#if defined(IBRT)
int hfp_ibrt_service_connected_mock(void) {
if (btif_get_hf_chan_state(app_bt_device.hf_channel[BT_DEVICE_ID_1]) ==
BTIF_HF_STATE_OPEN) {
TRACE(0, "::HF_EVENT_SERVICE_CONNECTED mock");
app_bt_device.hf_conn_flag[chan_id_flag.id] = 1;
} else {
TRACE(1, "::HF_EVENT_SERVICE_CONNECTED mock need check chan_state:%d",
btif_get_hf_chan_state(app_bt_device.hf_channel[BT_DEVICE_ID_1]));
}
return 0;
}
int hfp_ibrt_sync_get_status(ibrt_hfp_status_t *hfp_status) {
hfp_status->audio_state =
(uint8_t)app_bt_device.hf_audio_state[BT_DEVICE_ID_1];
hfp_status->volume = hfp_volume_get(BT_DEVICE_ID_1);
hfp_status->lmp_sco_hdl = 0;
if (hfp_status->audio_state == BTIF_HF_AUDIO_CON &&
app_tws_ibrt_mobile_link_connected()) {
ibrt_ctrl_t *p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx();
uint16_t sco_connhdl =
btif_me_get_scohdl_by_connhdl(p_ibrt_ctrl->mobile_conhandle);
hfp_status->lmp_sco_hdl = bt_drv_reg_op_lmp_sco_hdl_get(sco_connhdl);
TRACE(2, "ibrt_ui_log:get sco lmp hdl %04x %02x\n", sco_connhdl,
hfp_status->lmp_sco_hdl);
}
return 0;
}
int hfp_ibrt_sync_set_status(ibrt_hfp_status_t *hfp_status) {
ibrt_ctrl_t *p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx();
btif_remote_device_t *remDev = NULL;
TRACE(4, "%s audio_state:%d volume:%d lmp_scohdl:%02x", __func__,
hfp_status->audio_state, hfp_status->volume, hfp_status->lmp_sco_hdl);
app_bt_device.hf_audio_state[BT_DEVICE_ID_1] =
(btif_audio_state_t)hfp_status->audio_state;
if (app_tws_ibrt_mobile_link_connected()) {
remDev = btif_me_get_remote_device_by_handle(p_ibrt_ctrl->mobile_conhandle);
} else if (app_tws_ibrt_slave_ibrt_link_connected()) {
remDev = btif_me_get_remote_device_by_handle(p_ibrt_ctrl->ibrt_conhandle);
}
if (remDev) {
app_bt_stream_volume_ptr_update(
(uint8_t *)btif_me_get_remote_device_bdaddr(remDev));
} else {
app_bt_stream_volume_ptr_update(NULL);
}
hfp_volume_set(BT_DEVICE_ID_1, hfp_status->volume);
p_ibrt_ctrl->ibrt_sco_lmphdl = 0;
if (hfp_status->audio_state == BTIF_HF_AUDIO_CON &&
hfp_status->lmp_sco_hdl != 0 &&
app_tws_ibrt_slave_ibrt_link_connected()) {
uint16_t sco_connhdl = 0x0100; // SYNC_HFP_STATUS arrive before mock
// sniffer_sco, so use 0x0100 directly
if (bt_drv_reg_op_lmp_sco_hdl_set(sco_connhdl, hfp_status->lmp_sco_hdl)) {
TRACE(2, "ibrt_ui_log:set sco %04x lmp hdl %02x\n", sco_connhdl,
hfp_status->lmp_sco_hdl);
} else {
// SYNC_HFP_STATUS may so much faster lead bt_drv_reg_op_lmp_sco_hdl_set
// fail, backup the value
p_ibrt_ctrl->ibrt_sco_lmphdl = hfp_status->lmp_sco_hdl;
}
}
return 0;
}
int hfp_ibrt_sco_audio_connected(hfp_sco_codec_t codec, uint16_t sco_connhdl) {
int ret = BT_STS_SUCCESS;
ibrt_ctrl_t *p_ibrt_ctrl = NULL;
TRACE(0, "::HF_EVENT_AUDIO_CONNECTED mock");
app_bt_device.hf_audio_state[BT_DEVICE_ID_1] = BTIF_HF_AUDIO_CON;
btif_hf_set_negotiated_codec(app_bt_device.hf_channel[BT_DEVICE_ID_1], codec);
app_audio_manager_set_scocodecid(BT_DEVICE_ID_1, codec);
#ifdef ENABLE_HFP_AUDIO_PENDING_FOR_MEDIA
if (bt_media_cur_is_bt_stream_media()) {
app_hfp_set_starting_media_pending_flag(true, BT_DEVICE_ID_1);
} else
#endif
{
app_hfp_start_voice_media(BT_DEVICE_ID_1);
}
app_ibrt_if_sniff_checker_start(APP_IBRT_IF_SNIFF_CHECKER_USER_HFP);
struct bt_cb_tag *bt_drv_func_cb = bt_drv_get_func_cb_ptr();
if (bt_drv_func_cb->bt_switch_agc != NULL) {
bt_drv_func_cb->bt_switch_agc(BT_HFP_WORK_MODE);
}
p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx();
if (p_ibrt_ctrl->ibrt_sco_lmphdl != 0) {
// set backuped lmphdl if it is failed in hfp_ibrt_sync_set_status
TRACE(2, "ibrt_ui_log:set sco %04x lmp hdl %02x\n", sco_connhdl,
p_ibrt_ctrl->ibrt_sco_lmphdl);
bt_drv_reg_op_lmp_sco_hdl_set(sco_connhdl, p_ibrt_ctrl->ibrt_sco_lmphdl);
p_ibrt_ctrl->ibrt_sco_lmphdl = 0;
}
return ret;
}
int hfp_ibrt_sco_audio_disconnected(void) {
int ret = BT_STS_SUCCESS;
TRACE(0, "::HF_EVENT_AUDIO_DISCONNECTED mock");
app_bt_device.hf_audio_state[BT_DEVICE_ID_1] = BTIF_HF_AUDIO_DISCON;
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP, BT_STREAM_VOICE,
BT_DEVICE_ID_1, 0);
app_ibrt_if_sniff_checker_stop(APP_IBRT_IF_SNIFF_CHECKER_USER_HFP);
struct bt_cb_tag *bt_drv_func_cb = bt_drv_get_func_cb_ptr();
if (bt_drv_func_cb->bt_switch_agc != NULL) {
bt_drv_func_cb->bt_switch_agc(BT_IDLE_MODE);
}
return ret;
}
#endif