pinebuds/services/bt_app/app_a2dp_source.cpp

832 lines
31 KiB
C++

/***************************************************************************
*
* 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.
*
****************************************************************************/
#if defined(APP_LINEIN_A2DP_SOURCE) || defined(APP_I2S_A2DP_SOURCE)
#include "app_a2dp_source.h"
#include "a2dp_api.h"
#include "app_overlay.h"
uint8_t *a2dp_linein_buff;
static char a2dp_transmit_buffer[A2DP_TRANS_SIZE];
sbcbank_t sbcbank;
A2DP_SOURCE_STRUCT a2dp_source;
static sbcpack_t *get_sbcPacket(void) {
int index = sbcbank.free;
sbcbank.free += 1;
if (sbcbank.free == 1) {
sbcbank.free = 0;
}
return &(sbcbank.sbcpacks[index]);
}
#if 0
typedef struct {
AvrcpAdvancedPdu pdu;
uint8_t para_buf[10];
}APP_A2DP_AVRCPADVANCEDPDU;
extern osPoolId app_a2dp_avrcpadvancedpdu_mempool;
#define app_a2dp_avrcpadvancedpdu_mempool_init() \
do { \
if (app_a2dp_avrcpadvancedpdu_mempool == NULL) \
app_a2dp_avrcpadvancedpdu_mempool = \
osPoolCreate(osPool(app_a2dp_avrcpadvancedpdu_mempool)); \
} while (0);
#define app_a2dp_avrcpadvancedpdu_mempool_calloc(buf) \
do { \
APP_A2DP_AVRCPADVANCEDPDU *avrcpadvancedpdu; \
avrcpadvancedpdu = (APP_A2DP_AVRCPADVANCEDPDU *)osPoolCAlloc( \
app_a2dp_avrcpadvancedpdu_mempool); \
buf = &(avrcpadvancedpdu->pdu); \
buf->parms = avrcpadvancedpdu->para_buf; \
} while (0);
#define app_a2dp_avrcpadvancedpdu_mempool_free(buf) \
do { \
osPoolFree(app_a2dp_avrcpadvancedpdu_mempool, buf); \
} while (0);
void a2dp_source_volume_local_set(int8_t vol)
{
app_bt_stream_volume_get_ptr()->a2dp_vol = vol;
nv_record_touch_cause_flush();
}
static int a2dp_volume_get(void)
{
int vol = app_bt_stream_volume_get_ptr()->a2dp_vol;
vol = 8*vol-1;
if (vol > (0x7f-1))
vol = 0x7f;
return (vol);
}
static int a2dp_volume_set(U8 vol)
{
int dest_vol;
dest_vol = (((int)vol&0x7f)<<4)/0x7f + 1;
if (dest_vol > TGT_VOLUME_LEVEL_15)
dest_vol = TGT_VOLUME_LEVEL_15;
if (dest_vol < TGT_VOLUME_LEVEL_0)
dest_vol = TGT_VOLUME_LEVEL_0;
a2dp_source_volume_local_set(dest_vol);
app_bt_stream_volumeset(dest_vol);
return (vol);
}
void avrcp_source_callback_TG(AvrcpChannel *chnl, const AvrcpCallbackParms *Parms)
{
TRACE(3,"%s : chnl %p, Parms %p,Parms->event\n", __FUNCTION__,chnl, Parms,Parms->event);
enum BT_DEVICE_ID_T device_id = BT_DEVICE_ID_1;
switch(Parms->event)
{
case AVRCP_EVENT_CONNECT:
if(0)//(chnl->avrcpVersion >=0x103)
{
TRACE(1,"::%s AVRCP_GET_CAPABILITY\n",__FUNCTION__);
if (app_bt_device.avrcp_cmd1[device_id] == NULL)
app_a2dp_avrcpadvancedpdu_mempool_calloc(app_bt_device.avrcp_cmd1[device_id]);
AVRCP_CtGetCapabilities(chnl,app_bt_device.avrcp_cmd1[device_id],AVRCP_CAPABILITY_EVENTS_SUPPORTED);
}
app_bt_device.avrcp_channel[device_id].avrcpState = AVRCP_STATE_CONNECTED;
TRACE(3,"::%s AVRCP_EVENT_CONNECT %x,device_id=%d\n",__FUNCTION__, chnl->avrcpVersion,device_id);
break;
case AVRCP_EVENT_DISCONNECT:
TRACE(1,"::%s AVRCP_EVENT_DISCONNECT",__FUNCTION__);
app_bt_device.avrcp_channel[device_id].avrcpState = AVRCP_STATE_DISCONNECTED;
if (app_bt_device.avrcp_get_capabilities_rsp[device_id]){
app_a2dp_avrcpadvancedpdu_mempool_free(app_bt_device.avrcp_get_capabilities_rsp[device_id]);
app_bt_device.avrcp_get_capabilities_rsp[device_id] = NULL;
}
if (app_bt_device.avrcp_control_rsp[device_id]){
app_a2dp_avrcpadvancedpdu_mempool_free(app_bt_device.avrcp_control_rsp[device_id]);
app_bt_device.avrcp_control_rsp[device_id] = NULL;
}
if (app_bt_device.avrcp_notify_rsp[device_id]){
app_a2dp_avrcpadvancedpdu_mempool_free(app_bt_device.avrcp_notify_rsp[device_id]);
app_bt_device.avrcp_notify_rsp[device_id] = NULL;
}
if (app_bt_device.avrcp_cmd1[device_id]){
app_a2dp_avrcpadvancedpdu_mempool_free(app_bt_device.avrcp_cmd1[device_id]);
app_bt_device.avrcp_cmd1[device_id] = NULL;
}
if (app_bt_device.avrcp_cmd2[device_id]){
app_a2dp_avrcpadvancedpdu_mempool_free(app_bt_device.avrcp_cmd2[device_id]);
app_bt_device.avrcp_cmd2[device_id] = NULL;
}
app_bt_device.volume_report[device_id] = 0;
break;
case AVRCP_EVENT_RESPONSE:
TRACE(3,"::%s AVRCP_EVENT_RESPONSE op=%x,status=%x\n",__FUNCTION__, Parms->advOp,Parms->status);
break;
case AVRCP_EVENT_PANEL_CNF:
TRACE(4,"::%s AVRCP_EVENT_PANEL_CNF %x,%x,%x",__FUNCTION__,
Parms->p.panelCnf.response,Parms->p.panelCnf.operation,Parms->p.panelCnf.press);
break;
case AVRCP_EVENT_ADV_TX_DONE:
TRACE(4,"::%s AVRCP_EVENT_ADV_TX_DONE device_id=%d,status=%x,errorcode=%x\n",__FUNCTION__,device_id,Parms->status,Parms->errorCode);
TRACE(3,"::%s AVRCP_EVENT_ADV_TX_DONE op:%d, transid:%x\n", __FUNCTION__,Parms->p.adv.txPdu->op,Parms->p.adv.txPdu->transId);
if (Parms->p.adv.txPdu->op == AVRCP_OP_GET_CAPABILITIES){
if (app_bt_device.avrcp_get_capabilities_rsp[device_id] == Parms->p.adv.txPdu){
app_bt_device.avrcp_get_capabilities_rsp[device_id] = NULL;
app_a2dp_avrcpadvancedpdu_mempool_free(Parms->p.adv.txPdu);
}
}
break;
case AVRCP_EVENT_COMMAND:
#ifndef __AVRCP_EVENT_COMMAND_VOLUME_SKIP__
TRACE(3,"::%s AVRCP_EVENT_COMMAND device_id=%d,role=%x\n",__FUNCTION__,device_id,chnl->role);
TRACE(3,"::%s AVRCP_EVENT_COMMAND ctype=%x,subunitype=%x\n",__FUNCTION__, Parms->p.cmdFrame->ctype,Parms->p.cmdFrame->subunitType);
TRACE(3,"::%s AVRCP_EVENT_COMMAND subunitId=%x,opcode=%x\n",__FUNCTION__, Parms->p.cmdFrame->subunitId,Parms->p.cmdFrame->opcode);
TRACE(3,"::%s AVRCP_EVENT_COMMAND operands=%x,operandLen=%x\n",__FUNCTION__, Parms->p.cmdFrame->operands,Parms->p.cmdFrame->operandLen);
TRACE(2,"::%s AVRCP_EVENT_COMMAND more=%x\n", Parms->p.cmdFrame->more);
if(Parms->p.cmdFrame->ctype == AVRCP_CTYPE_STATUS)
{
uint32_t company_id = *(Parms->p.cmdFrame->operands+2) + ((uint32_t)(*(Parms->p.cmdFrame->operands+1))<<8) + ((uint32_t)(*(Parms->p.cmdFrame->operands))<<16);
TRACE(2,"::%s AVRCP_EVENT_COMMAND company_id=%x\n",__FUNCTION__, company_id);
if(company_id == 0x001958) //bt sig
{
AvrcpOperation op = *(Parms->p.cmdFrame->operands+3);
uint8_t oplen = *(Parms->p.cmdFrame->operands+6)+ ((uint32_t)(*(Parms->p.cmdFrame->operands+5))<<8);
TRACE(3,"::%s AVRCP_EVENT_COMMAND op=%x,oplen=%x\n",__FUNCTION__, op,oplen);
switch(op)
{
case AVRCP_OP_GET_CAPABILITIES:
{
uint8_t event = *(Parms->p.cmdFrame->operands+7);
if(event==AVRCP_CAPABILITY_COMPANY_ID)
{
TRACE(1,"::%s AVRCP_EVENT_COMMAND send support compay id",__FUNCTION__);
}
else if(event == AVRCP_CAPABILITY_EVENTS_SUPPORTED)
{
TRACE(2,"::%s AVRCP_EVENT_COMMAND send support event transId:%d", __FUNCTION__,Parms->p.cmdFrame->transId);
chnl->adv.eventMask = AVRCP_ENABLE_VOLUME_CHANGED; ///volume control
if (app_bt_device.avrcp_get_capabilities_rsp[device_id] == NULL)
app_a2dp_avrcpadvancedpdu_mempool_calloc(app_bt_device.avrcp_get_capabilities_rsp[device_id]);
app_bt_device.avrcp_get_capabilities_rsp[device_id]->transId = Parms->p.cmdFrame->transId;
app_bt_device.avrcp_get_capabilities_rsp[device_id]->ctype = AVCTP_RESPONSE_IMPLEMENTED_STABLE;
TRACE(2,"::%s AVRCP_EVENT_COMMAND send support event transId:%d", __FUNCTION__,app_bt_device.avrcp_get_capabilities_rsp[device_id]->transId);
AVRCP_CtGetCapabilities_Rsp(chnl,app_bt_device.avrcp_get_capabilities_rsp[device_id],AVRCP_CAPABILITY_EVENTS_SUPPORTED,chnl->adv.eventMask);
}
else
{
TRACE(1,"::%s AVRCP_EVENT_COMMAND send error event value",__FUNCTION__);
}
}
break;
}
}
}else if(Parms->p.cmdFrame->ctype == AVCTP_CTYPE_CONTROL){
TRACE(1,"::%s AVRCP_EVENT_COMMAND AVCTP_CTYPE_CONTROL\n",__FUNCTION__);
DUMP8("%02x ", Parms->p.cmdFrame->operands, Parms->p.cmdFrame->operandLen);
if (Parms->p.cmdFrame->operands[3] == AVRCP_OP_SET_ABSOLUTE_VOLUME){
TRACE(2,"::%s AVRCP_EID_VOLUME_CHANGED transId:%d\n", __FUNCTION__,Parms->p.cmdFrame->transId);
a2dp_volume_set(Parms->p.cmdFrame->operands[7]);
if (app_bt_device.avrcp_control_rsp[device_id] == NULL)
app_a2dp_avrcpadvancedpdu_mempool_calloc(app_bt_device.avrcp_control_rsp[device_id]);
app_bt_device.avrcp_control_rsp[device_id]->transId = Parms->p.cmdFrame->transId;
app_bt_device.avrcp_control_rsp[device_id]->ctype = AVCTP_RESPONSE_ACCEPTED;
DUMP8("%02x ", Parms->p.cmdFrame->operands, Parms->p.cmdFrame->operandLen);
AVRCP_CtAcceptAbsoluteVolume_Rsp(chnl, app_bt_device.avrcp_control_rsp[device_id], Parms->p.cmdFrame->operands[7]);
}
}else if (Parms->p.cmdFrame->ctype == AVCTP_CTYPE_NOTIFY){
BtStatus status;
TRACE(1,"::%s AVRCP_EVENT_COMMAND AVCTP_CTYPE_NOTIFY\n",__FUNCTION__);
DUMP8("%02x ", Parms->p.cmdFrame->operands, Parms->p.cmdFrame->operandLen);
if (Parms->p.cmdFrame->operands[7] == AVRCP_EID_VOLUME_CHANGED){
TRACE(2,"::%s AVRCP_EID_VOLUME_CHANGED transId:%d\n", __FUNCTION__,Parms->p.cmdFrame->transId);
if (app_bt_device.avrcp_notify_rsp[device_id] == NULL)
app_a2dp_avrcpadvancedpdu_mempool_calloc(app_bt_device.avrcp_notify_rsp[device_id]);
app_bt_device.avrcp_notify_rsp[device_id]->transId = Parms->p.cmdFrame->transId;
app_bt_device.avrcp_notify_rsp[device_id]->ctype = AVCTP_RESPONSE_INTERIM;
app_bt_device.volume_report[device_id] = AVCTP_RESPONSE_INTERIM;
status = AVRCP_CtGetAbsoluteVolume_Rsp(chnl, app_bt_device.avrcp_notify_rsp[device_id], a2dp_volume_get());
TRACE(2,"::%s AVRCP_EVENT_COMMAND AVRCP_EID_VOLUME_CHANGED nRet:%x\n",__FUNCTION__,status);
}
}
#endif
break;
case AVRCP_EVENT_ADV_CMD_TIMEOUT:
TRACE(3,"::%s AVRCP_EVENT_ADV_CMD_TIMEOUT device_id=%d,role=%x\n",__FUNCTION__,device_id,chnl->role);
break;
}
}
#endif
osMutexId a2dp_source_mutex_id = NULL;
osMutexDef(a2dp_source_mutex);
static void a2dp_source_mutex_lock(void) {
osMutexWait(a2dp_source_mutex_id, osWaitForever);
}
static void a2dp_source_mutex_unlock(void) {
osMutexRelease(a2dp_source_mutex_id);
}
static void a2dp_source_sem_lock(a2dp_source_lock_t *lock) {
osSemaphoreWait(lock->_osSemaphoreId, osWaitForever);
}
static void a2dp_source_sem_unlock(a2dp_source_lock_t *lock) {
osSemaphoreRelease(lock->_osSemaphoreId);
}
static void a2dp_source_reset_send_lock(void) {
PSCB p_scb = (PSCB)(a2dp_source.sbc_send_lock._osSemaphoreDef.semaphore);
uint32_t lock = int_lock();
p_scb->tokens = 0;
int_unlock(lock);
}
static bool a2dp_source_is_send_wait(void) {
bool ret = false;
uint32_t lock = int_lock();
PSCB p_scb = (PSCB)(a2dp_source.sbc_send_lock._osSemaphoreDef.semaphore);
if (p_scb->p_lnk) {
ret = true;
}
int_unlock(lock);
return ret;
}
static void a2dp_source_wait_pcm_data(void) {
a2dp_source_lock_t *lock = &(a2dp_source.data_lock);
PSCB p_scb = (PSCB)(lock->_osSemaphoreDef.semaphore);
uint32_t iflag = int_lock();
p_scb->tokens = 0;
int_unlock(iflag);
a2dp_source_sem_lock(lock);
}
static void a2dp_source_put_data(void) {
a2dp_source_lock_t *lock = &(a2dp_source.data_lock);
a2dp_source_sem_unlock(lock);
}
#if 0
static void a2dp_source_lock_sbcsending(void * channel)
{
tws_lock_t *lock = &(a2dp_source.sbc_send_lock);
sem_lock(lock);
}
static void a2dp_source_unlock_sbcsending(void * channel)
{
tws_lock_t *lock = &(a2dp_source.sbc_send_lock);
sem_unlock(lock);
}
#endif
static int32_t a2dp_source_wait_sent(uint32_t timeout) {
int32_t ret = 0;
a2dp_source_lock_t *lock = &(a2dp_source.sbc_send_lock);
a2dp_source_reset_send_lock();
ret = osSemaphoreWait(lock->_osSemaphoreId, timeout);
return ret;
}
void a2dp_source_notify_send(void) {
if (a2dp_source_is_send_wait()) { // task wait lock
// TWS_DBLOG("\nNOTIFY SEND\n");
a2dp_source_sem_unlock(&(a2dp_source.sbc_send_lock));
}
}
// loop write
static int A2dpSourceEnCQueue(CQueue *Q, CQItemType *e, unsigned int len) {
int status = CQ_OK;
if (AvailableOfCQueue(Q) < (int)len) {
Q->write = 0;
Q->len = 0;
Q->read = 0;
status = CQ_ERR;
} else {
status = CQ_OK;
}
Q->len += len;
while (len > 0) {
Q->base[Q->write] = *e;
++Q->write;
++e;
--len;
if (Q->write >= Q->size)
Q->write = 0;
}
// TRACE(1,"Q->len:%d ", Q->len);
return status;
}
static int a2dp_source_pcm_buffer_write(uint8_t *pcm_buf, uint16_t len) {
int status;
// TWS_DBLOG("\nenter: %s %d\n",__FUNCTION__,__LINE__);
a2dp_source_mutex_lock();
status = A2dpSourceEnCQueue(&(a2dp_source.pcm_queue), pcm_buf, len);
a2dp_source_mutex_unlock();
// TWS_DBLOG("\nexit: %s %d\n",__FUNCTION__,__LINE__);
return status;
}
static int a2dp_source_pcm_buffer_read(uint8_t *buff, uint16_t len) {
uint8_t *e1 = NULL, *e2 = NULL;
unsigned int len1 = 0, len2 = 0;
int status;
a2dp_source_mutex_lock();
status = PeekCQueue(&(a2dp_source.pcm_queue), len, &e1, &len1, &e2, &len2);
if (len == (len1 + len2)) {
memcpy(buff, e1, len1);
memcpy(buff + len1, e2, len2);
DeCQueue(&(a2dp_source.pcm_queue), 0, len);
} else {
// SOURCE_DBLOG("memset buffer");
memset(buff, 0x00, len);
status = -1;
}
a2dp_source_mutex_unlock();
return status;
}
uint32_t a2dp_source_linein_more_pcm_data(uint8_t *pcm_buf, uint32_t len) {
#if 1
int status;
status = a2dp_source_pcm_buffer_write(pcm_buf, len);
// pcm data from adc
// DUMP8("%02x ",pcm_buf, 10);
if (status != CQ_OK) {
SOURCE_DBLOG("linin buff overflow!");
}
a2dp_source_put_data();
return len;
#else
int status;
status = a2dp_source_pcm_buffer_write(pcm_buf, len);
// pcm data from adc
// DUMP8("%02x ",pcm_buf, 10);
if (status != CQ_OK) {
SOURCE_DBLOG("linin buff overflow!");
}
if (((app_bt_device.input_onoff == 1) &&
(a2dp_source.pcm_queue.len > 10 * 1024)) ||
(app_bt_device.input_onoff == 2)) {
a2dp_source_put_data();
app_bt_device.input_onoff = 2;
}
return len;
#endif
}
static btif_handler a2dp_source_handler;
static uint8_t app_a2dp_source_find_process = 0;
void app_a2dp_source_stop_find(void) {
app_a2dp_source_find_process = 0;
// ME_UnregisterGlobalHandler(&a2dp_source_handler);
}
#if 0
static void bt_a2dp_source_call_back(const BtEvent* event)
{
switch (event->eType) {
case BTEVENT_HCI_COMMAND_SENT:
case BTEVENT_ACL_DATA_NOT_ACTIVE:
return;
case BTEVENT_ACL_DATA_ACTIVE:
CmgrHandler *cmgrHandler;
/* Start the sniff timer */
cmgrHandler = CMGR_GetAclHandler(event->p.remDev);
if (cmgrHandler)
app_bt_CMGR_SetSniffTimer(cmgrHandler, NULL, CMGR_SNIFF_TIMER);
return;
}
TRACE(1,"SRC app_bt_golbal_handle evt = %d",event->eType);
switch(event->eType){
case BTEVENT_NAME_RESULT:
SOURCE_DBLOG("\n%s %d BTEVENT_NAME_RESULT\n",__FUNCTION__,__LINE__);
break;
case BTEVENT_INQUIRY_RESULT:
SOURCE_DBLOG("\n%s %d BTEVENT_INQUIRY_RESULT\n",__FUNCTION__,__LINE__);
DUMP8("%02x ", event->p.inqResult.bdAddr.addr, 6);
SOURCE_DBLOG("inqmode = %x",event->p.inqResult.inqMode);
DUMP8("%02x ", event->p.inqResult.extInqResp, 20);
SOURCE_DBLOG("classdevice=%x",event->p.inqResult.classOfDevice);
///check the class of device to find the handfree device
if(event->p.inqResult.classOfDevice & COD_MAJOR_AUDIO)
//if((event->p.inqResult.classOfDevice & COD_MAJOR_AUDIO)&&(!memcmp(event->p.inqResult.bdAddr.addr,"\x36\x35\x34",3)))
{
memcpy(app_bt_device.inquried_snk_bdAddr.addr,event->p.inqResult.bdAddr.addr,sizeof(event->p.inqResult.bdAddr.addr));
DUMP8("%02x ",app_bt_device.inquried_snk_bdAddr.addr, 6);
ME_CancelInquiry();
app_a2dp_source_stop_find();
}
break;
case BTEVENT_INQUIRY_COMPLETE:
SOURCE_DBLOG("\n%s %d BTEVENT_INQUIRY_COMPLETE\n",__FUNCTION__,__LINE__);
app_a2dp_source_stop_find();
break;
/** The Inquiry process is canceled. */
case BTEVENT_INQUIRY_CANCELED:
SOURCE_DBLOG("\n%s %d BTEVENT_INQUIRY_CANCELED\n",__FUNCTION__,__LINE__);
SOURCE_DBLOG("start to connect peer device");
A2DP_OpenStream(&app_bt_device.a2dp_stream[BT_DEVICE_ID_1], (BT_BD_ADDR *)&app_bt_device.inquried_snk_bdAddr);
break;
case BTEVENT_LINK_CONNECT_CNF:
case BTEVENT_LINK_CONNECT_IND:
SOURCE_DBLOG("CONNECT_IND/CNF evt:%d errCode:0x%0x newRole:%d activeCons:%d",event->eType, event->errCode, event->p.remDev->role, MEC(activeCons));
#if defined(__BTIF_EARPHONE__) && defined(__BTIF_AUTOPOWEROFF__)
if (MEC(activeCons) == 0){
app_start_10_second_timer(APP_POWEROFF_TIMER_ID);
}else{
app_stop_10_second_timer(APP_POWEROFF_TIMER_ID);
}
#endif
if (MEC(activeCons) > 1){
app_bt_MeDisconnectLink(event->p.remDev);
}
default:
//SOURCE_DBLOG("\n%s %d etype:%d\n",__FUNCTION__,__LINE__,event->eType);
break;
}
app_bt_role_manager_process(event);
app_bt_accessible_manager_process(event);
app_bt_sniff_manager_process(event);
app_bt_golbal_handle_hook(event);
//SOURCE_DBLOG("\nexit: %s %d\n",__FUNCTION__,__LINE__);
}
#else
uint8_t source_bt_addr[6] = {0x88, 0xaa, 0x33, 0x22, 0x11, 0x11};
// uint8_t source_bt_addr[6]={0x85,0x7e,0xaa,0x3c,0xd0,0xe8};
static void bt_a2dp_source_call_back(const btif_event_t *Event) {
uint8_t etype = btif_me_get_callback_event_type(Event);
btif_remote_device_t *remDev;
switch (etype) {
case BTIF_BTEVENT_HCI_COMMAND_SENT:
case BTIF_BTEVENT_ACL_DATA_NOT_ACTIVE:
return;
case BTIF_BTEVENT_ACL_DATA_ACTIVE:
btif_cmgr_handler_t *cmgrHandler;
/* Start the sniff timer */
cmgrHandler =
btif_cmgr_get_acl_handler(btif_me_get_callback_event_rem_dev(Event));
if (cmgrHandler)
app_bt_CMGR_SetSniffTimer(cmgrHandler, NULL, BTIF_CMGR_SNIFF_TIMER);
return;
}
TRACE(1, "SRC app_bt_golbal_handle evt = %d", etype);
switch (etype) {
case BTIF_BTEVENT_NAME_RESULT:
SOURCE_DBLOG("\n%s %d BTEVENT_NAME_RESULT\n", __FUNCTION__, __LINE__);
break;
case BTIF_BTEVENT_INQUIRY_RESULT:
remDev = btif_me_get_callback_event_rem_dev(Event);
SOURCE_DBLOG("\n%s %d BTEVENT_INQUIRY_RESULT\n", __FUNCTION__, __LINE__);
DUMP8("%02x ", btif_me_get_callback_event_inq_result_bd_addr_addr(Event),
6);
SOURCE_DBLOG("inqmode = %x",
btif_me_get_callback_event_inq_result_inq_mode(Event));
DUMP8("%02x ", btif_me_get_callback_event_inq_result_ext_inq_resp(Event),
20);
SOURCE_DBLOG("classdevice=%x",
btif_me_get_callback_event_inq_result_classofdevice(Event));
/// check the class of device to find the handfree device
// if(btif_me_get_callback_event_inq_result_classofdevice(Event) &
// BTIF_COD_MAJOR_AUDIO)
if ((btif_me_get_callback_event_inq_result_classofdevice(Event) &
BTIF_COD_MAJOR_AUDIO) &&
(!memcmp(btif_me_get_callback_event_inq_result_bd_addr_addr(Event),
source_bt_addr, 6))) {
memcpy(app_bt_device.inquried_snk_bdAddr.addr,
btif_me_get_callback_event_inq_result_bd_addr_addr(Event), 6);
DUMP8("%02x ", app_bt_device.inquried_snk_bdAddr.addr, 6);
btif_me_cancel_inquiry();
app_a2dp_source_stop_find();
}
break;
case BTIF_BTEVENT_INQUIRY_COMPLETE:
SOURCE_DBLOG("\n%s %d BTEVENT_INQUIRY_COMPLETE\n", __FUNCTION__, __LINE__);
app_a2dp_source_stop_find();
break;
/** The Inquiry process is canceled. */
case BTIF_BTEVENT_INQUIRY_CANCELED:
SOURCE_DBLOG("\n%s %d BTEVENT_INQUIRY_CANCELED\n", __FUNCTION__, __LINE__);
SOURCE_DBLOG("start to connect peer device");
btif_a2dp_open_stream(
app_bt_device.a2dp_stream[BT_DEVICE_ID_1]->a2dp_stream,
(bt_bdaddr_t *)&app_bt_device.inquried_snk_bdAddr);
break;
case BTIF_BTEVENT_LINK_CONNECT_CNF:
case BTIF_BTEVENT_LINK_CONNECT_IND:
SOURCE_DBLOG(
"CONNECT_IND/CNF evt:%d errCode:0x%0x newRole:%d activeCons:%d", etype,
btif_me_get_callback_event_err_code(Event),
btif_me_get_remote_device_role(
btif_me_get_callback_event_rem_dev(Event)),
btif_me_get_activeCons());
#if defined(__BTIF_EARPHONE__) && defined(__BTIF_AUTOPOWEROFF__)
if (btif_me_get_activeCons() == 0) {
app_start_10_second_timer(APP_POWEROFF_TIMER_ID);
} else {
app_stop_10_second_timer(APP_POWEROFF_TIMER_ID);
}
#endif
if (btif_me_get_activeCons() > 1) {
remDev = btif_me_get_callback_event_rem_dev(Event);
app_bt_MeDisconnectLink(remDev);
}
default:
// SOURCE_DBLOG("\n%s %d etype:%d\n",__FUNCTION__,__LINE__,event->eType);
break;
}
app_bt_role_manager_process(Event);
app_bt_accessible_manager_process(Event);
app_bt_sniff_manager_process(Event);
// SOURCE_DBLOG("\nexit: %s %d\n",__FUNCTION__,__LINE__);
}
#endif
void app_a2dp_start_stream(void) {
btif_a2dp_start_stream(&app_bt_device.a2dp_stream[BT_DEVICE_ID_1]);
}
void app_a2dp_suspend_stream(void) {
btif_a2dp_suspend_stream(&app_bt_device.a2dp_stream[BT_DEVICE_ID_1]);
}
static void _find_a2dp_sink_peer_device_start(void) {
SOURCE_DBLOG("\nenter: %s %d\n", __FUNCTION__, __LINE__);
bt_status_t state;
if (app_a2dp_source_find_process == 0 && app_bt_device.a2dp_state[0] == 0) {
app_a2dp_source_find_process = 1;
again:
state = btif_me_inquiry(BTIF_BT_IAC_GIAC, 30, 0);
SOURCE_DBLOG("\n%s %d\n", __FUNCTION__, __LINE__);
if (state != BT_STS_PENDING) {
osDelay(500);
goto again;
}
SOURCE_DBLOG("\n%s %d\n", __FUNCTION__, __LINE__);
}
}
void app_a2dp_source_find_sink(void) { _find_a2dp_sink_peer_device_start(); }
static bool need_init_encoder = true;
//__PSRAMDATA static SbcStreamInfo StreamInfo = {0};
static btif_sbc_stream_info_short_t StreamInfo = {0};
static btif_sbc_encoder_t sbc_encoder;
static uint8_t
app_a2dp_source_samplerate_2_sbcenc_type(enum AUD_SAMPRATE_T sample_rate) {
uint8_t rate = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
switch (sample_rate) {
case AUD_SAMPRATE_16000:
rate = BTIF_SBC_CHNL_SAMPLE_FREQ_16;
break;
case AUD_SAMPRATE_32000:
rate = BTIF_SBC_CHNL_SAMPLE_FREQ_32;
break;
case AUD_SAMPRATE_44100:
rate = BTIF_SBC_CHNL_SAMPLE_FREQ_44_1;
break;
case AUD_SAMPRATE_48000:
rate = BTIF_SBC_CHNL_SAMPLE_FREQ_48;
break;
default:
TRACE(0, "error! sbc enc don't support other samplerate");
break;
}
SOURCE_DBLOG("\n%s %d rate = %x\n", __FUNCTION__, __LINE__, rate);
return rate;
}
#if 1
static void a2dp_source_send_sbc_packet(void) {
uint32_t frame_size = 512;
uint32_t frame_num = A2DP_TRANS_SIZE / frame_size;
// a2dp_source.lock_stream(&(tws.tws_source));
uint16_t byte_encoded = 0;
// uint16_t pcm_frame_size = 512/2;
unsigned short enc_len = 0;
bt_status_t status = BT_STS_FAILED;
int lock = int_lock();
sbcpack_t *sbcpack = get_sbcPacket();
btif_a2dp_sbc_packet_t *sbcPacket = &(sbcpack->sbcPacket);
sbcPacket->data = (U8 *)sbcpack->buffer;
memcpy(sbcpack->buffer, a2dp_transmit_buffer, A2DP_TRANS_SIZE);
// sbcPacket->dataLen = len;
// sbcPacket->frameSize = len/frame_num;
btif_sbc_pcm_data_t PcmEncData;
if (need_init_encoder) {
btif_sbc_init_encoder(&sbc_encoder);
sbc_encoder.streamInfo.numChannels = 2;
sbc_encoder.streamInfo.channelMode = BTIF_SBC_CHNL_MODE_JOINT_STEREO;
sbc_encoder.streamInfo.bitPool = A2DP_SBC_BITPOOL;
sbc_encoder.streamInfo.sampleFreq =
app_a2dp_source_samplerate_2_sbcenc_type(a2dp_source.sample_rate);
sbc_encoder.streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_SNR;
sbc_encoder.streamInfo.numBlocks = 16;
sbc_encoder.streamInfo.numSubBands = 8;
sbc_encoder.streamInfo.mSbcFlag = 0;
need_init_encoder = 0;
}
PcmEncData.data = (uint8_t *)a2dp_transmit_buffer;
PcmEncData.dataLen = A2DP_TRANS_SIZE;
PcmEncData.numChannels = 2;
PcmEncData.sampleFreq = sbc_encoder.streamInfo.sampleFreq;
btif_sbc_encode_frames(&sbc_encoder, &PcmEncData, &byte_encoded,
(unsigned char *)sbcpack->buffer, &enc_len,
A2DP_TRANS_SIZE);
sbcPacket->dataLen = enc_len;
sbcPacket->frameSize = enc_len / frame_num;
int_unlock(lock);
status = btif_a2dp_stream_send_sbc_packet(
app_bt_device.a2dp_stream[BT_DEVICE_ID_1]->a2dp_stream, sbcPacket,
&StreamInfo);
if (status == BT_STS_PENDING)
a2dp_source_wait_sent(osWaitForever);
}
#endif
// #define BT_A2DP_SOURCE_LINEIN_BUFF_SIZE (512*5*2*2)
#define BT_A2DP_SOURCE_LINEIN_BUFF_SIZE (A2DP_TRANS_SIZE * 2)
#if defined(APP_LINEIN_A2DP_SOURCE)
//////////start the audio linein stream for capure the pcm data
int app_a2dp_source_linein_on(bool on) {
uint8_t *buff_play = NULL;
struct AF_STREAM_CONFIG_T stream_cfg;
static bool isRun = false;
SOURCE_DBLOG("app_a2dp_source_linein_on work:%d op:%d", isRun, on);
if (isRun == on)
return 0;
if (on) {
#if defined(SLAVE_USE_OPUS) || defined(MASTER_USE_OPUS) || defined(ALL_USE_OPUS)
app_audio_mempool_init(app_audio_get_basebuf_ptr(APP_MEM_LINEIN_AUDIO),
app_audio_get_basebuf_size(APP_MEM_LINEIN_AUDIO));
#else
app_audio_mempool_init();
#endif
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_104M);
app_audio_mempool_get_buff(&buff_play, BT_A2DP_SOURCE_LINEIN_BUFF_SIZE);
memset(&stream_cfg, 0, sizeof(stream_cfg));
stream_cfg.bits = AUD_BITS_16;
stream_cfg.channel_num = AUD_CHANNEL_NUM_2;
stream_cfg.sample_rate = a2dp_source.sample_rate;
stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
stream_cfg.vol = 10;
// stream_cfg.io_path = AUD_INPUT_PATH_HP_MIC;
// stream_cfg.io_path =AUD_INPUT_PATH_MAINMIC;
stream_cfg.io_path = AUD_INPUT_PATH_LINEIN;
stream_cfg.handler = a2dp_source_linein_more_pcm_data;
stream_cfg.data_ptr = buff_play;
stream_cfg.data_size = BT_A2DP_SOURCE_LINEIN_BUFF_SIZE;
af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);
af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
SOURCE_DBLOG("app_source_linein_on on");
} else {
af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
SOURCE_DBLOG("app_source_linein_on off");
// clear buffer data
a2dp_source.pcm_queue.write = 0;
a2dp_source.pcm_queue.len = 0;
a2dp_source.pcm_queue.read = 0;
app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);
}
isRun = on;
return 0;
}
#endif
////////////////////////////creat the thread for send sbc data to a2dp sink
/// device ///////////////////
static void send_thread(const void *arg);
osThreadDef(send_thread, osPriorityHigh, 1, 1024 * 2, "a2dp_send");
#if 1
static void send_thread(const void *arg) {
while (1) {
a2dp_source_wait_pcm_data();
while (a2dp_source_pcm_buffer_read((uint8_t *)a2dp_transmit_buffer,
A2DP_TRANS_SIZE) == 0) {
a2dp_source_send_sbc_packet();
}
}
}
#endif
void app_source_init(void) {
// register the bt global handler
a2dp_source_handler.callback = bt_a2dp_source_call_back;
btif_me_register_global_handler(&a2dp_source_handler);
btif_me_set_event_mask(
&a2dp_source_handler,
BTIF_BEM_LINK_DISCONNECT | BTIF_BEM_ROLE_CHANGE |
BTIF_BEM_INQUIRY_RESULT | BTIF_BEM_INQUIRY_COMPLETE |
BTIF_BEM_INQUIRY_CANCELED | BTIF_BEM_LINK_CONNECT_CNF |
BTIF_BEM_LINK_CONNECT_IND);
}
///////init the a2dp source feature
void app_a2dp_source_init(void) {
a2dp_source_lock_t *lock;
// get heap from app_audio_buffer
app_audio_mempool_get_buff(&a2dp_linein_buff, A2DP_LINEIN_SIZE);
InitCQueue(&a2dp_source.pcm_queue, A2DP_LINEIN_SIZE,
(CQItemType *)a2dp_linein_buff);
if (a2dp_source_mutex_id == NULL) {
a2dp_source_mutex_id = osMutexCreate((osMutex(a2dp_source_mutex)));
}
lock = &(a2dp_source.data_lock);
memset(lock, 0, sizeof(a2dp_source_lock_t));
lock->_osSemaphoreDef.semaphore = lock->_semaphore_data;
lock->_osSemaphoreId = osSemaphoreCreate(&(lock->_osSemaphoreDef), 0);
lock = &(a2dp_source.sbc_send_lock);
memset(lock, 0, sizeof(a2dp_source_lock_t));
lock->_osSemaphoreDef.semaphore = lock->_semaphore_data;
lock->_osSemaphoreId = osSemaphoreCreate(&(lock->_osSemaphoreDef), 0);
a2dp_source.sbc_send_id = osThreadCreate(osThread(send_thread), NULL);
a2dp_source.sample_rate = AUD_SAMPRATE_44100;
}
#endif