MXC-A36-Demo/MCU/examples/application/btdm_audio/Src/app_bt.c

1285 lines
48 KiB
C
Raw Permalink Normal View History

#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "btdm_host.h"
#include "fdb_app.h"
#include "app_config.h"
#include "app_bt.h"
#include "user_bt.h"
#ifndef LOG_ENABLE
#define LOG_ENABLE
#endif
#include "co_log.h"
#ifdef LOG_LOCAL_LEVEL
#undef LOG_LOCAL_LEVEL
#endif
#define LOG_LOCAL_LEVEL LOG_LEVEL_INFO
#define NUM_STREAMS 4
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) > (b) ? (b) : (a))
const BtAccessModeInfo access_mode_nc = {
.inqInterval = 0x800,
.inqWindow = 0x12,
.pageInterval = 0x800,
.pageWindow = 0x12,
};
static BtHandler securityHandler;
static BtHandler globalHandler;
static BtSecurityParms secParms;
static char hf_codec[2];
uint8_t default_name[] = "FR30xx_0000";
//HfChannel hf_channel[NUM_BT_DEVICES];
//HfgChannel hfg_channel[NUM_BT_DEVICES];
//A2dpStream Stream[NUM_STREAMS];
//AvrcpChannel rcpCtChannel[NUM_BT_DEVICES];
//AvrcpChannel rcpTgChannel[NUM_BT_DEVICES];
HfChannel *hf_channel;
HfgChannel *hfg_channel;
A2dpStream *Stream;
AvrcpChannel *rcpCtChannel;
AvrcpChannel *rcpTgChannel;
PbapClientSession *pbap_client; /* PBAP client */
SppDev *spp_dev;
//BtPacket *scoPacket;
uint8_t SbcSnkElements[]={
A2DP_SBC_CODEC_INF_ELEMENT(
/* 48000 and 44100 are required for SNK */
A2DP_SBC_CODEC_FREQ_48000 |
A2DP_SBC_CODEC_FREQ_44100 |
A2DP_SBC_CODEC_FREQ_32000 |
A2DP_SBC_CODEC_FREQ_16000,
/* All modes required for SNK */
A2DP_SBC_CODEC_CHNL_MODE_MONO |
A2DP_SBC_CODEC_CHNL_MODE_DUAL |
A2DP_SBC_CODEC_CHNL_MODE_STEREO |
A2DP_SBC_CODEC_CHNL_MODE_JOINT,
/* One block size must be supported */
A2DP_SBC_CODEC_BLOCKS_16 |
A2DP_SBC_CODEC_BLOCKS_12 |
A2DP_SBC_CODEC_BLOCKS_8 |
A2DP_SBC_CODEC_BLOCKS_4,
/* Both 8 and 4 must be supported */
A2DP_SBC_CODEC_SUBBANDS_8 |
A2DP_SBC_CODEC_SUBBANDS_4,
/* Both allocation methods must be supported in SNK */
A2DP_SBC_CODEC_ALLOCATION_LOUDNESS |
A2DP_SBC_CODEC_ALLOCATION_SNR,
/* Minium bitpool */
2,
/* Maximum bitpool */
53)
};
uint8_t AacSnkElements[] = {
A2DP_AAC_CODEC_MPEG2_LC |
A2DP_AAC_CODEC_MPEG4_LC,
A2DP_AAC_CODEC_FREQ_44100,
A2DP_AAC_CODEC_FREQ_48000 |
A2DP_AAC_CODEC_CHNL_MONO |
A2DP_AAC_CODEC_CHNL_STEREO,
A2DP_AAC_CODEC_VBR,
0x00, 0x00
};
/* Source SBC Elements */
static uint8_t SbcSrcElements[] = {
A2DP_SBC_CODEC_INF_ELEMENT(/* 48000 or 44100 is required for SRC */
/*A2DP_SBC_CODEC_FREQ_48000 | */
A2DP_SBC_CODEC_FREQ_44100 /*|
A2DP_SBC_CODEC_FREQ_32000 |
A2DP_SBC_CODEC_FREQ_16000*/,
/* MONO and one other required for SRC */
A2DP_SBC_CODEC_CHNL_MODE_MONO |
A2DP_SBC_CODEC_CHNL_MODE_DUAL |
A2DP_SBC_CODEC_CHNL_MODE_STEREO |
A2DP_SBC_CODEC_CHNL_MODE_JOINT,
/* One block size must be supported */
A2DP_SBC_CODEC_BLOCKS_16 |
A2DP_SBC_CODEC_BLOCKS_12 |
A2DP_SBC_CODEC_BLOCKS_8 |
A2DP_SBC_CODEC_BLOCKS_4,
/* SRC must support 8 subbands */
A2DP_SBC_CODEC_SUBBANDS_8 |
A2DP_SBC_CODEC_SUBBANDS_4,
/* SRC must support LOUDNESS */
A2DP_SBC_CODEC_ALLOCATION_LOUDNESS |
A2DP_SBC_CODEC_ALLOCATION_SNR,
/* Minium bitpool */
2,
/* Maximum bitpool */
53)
};
AvdtpCodec sbcSnkCodec1; //local codec information
AvdtpCodec aacSnkCodec1;
AvdtpCodec sbcSnkCodec2; //local codec information
AvdtpCodec aacSnkCodec2;
AvdtpCodec sbcSrcCodec1;
AvdtpCodec sbcSrcCodec2;
static AvdtpCodec cfgCodec;
static uint8_t cfgElements[4];
static app_btdm_callback_t btdm_cb = NULL;
extern void CMGR_SetAudioVoiceSettings(BtScoAudioSettings settings);
uint8_t bt_get_free_hf_channel(void)
{
uint8_t index = 0;
for(index = 0; index < NUM_BT_DEVICES; index++){
if(hf_channel[index].state == HF_STATE_CLOSED){
break;
}
}
return index;
}
uint8_t bt_get_free_hfg_channel(void)
{
uint8_t index = 0;
for(index = 0; index < NUM_BT_DEVICES; index++){
if(hfg_channel[index].state == HFG_STATE_CLOSED){
break;
}
}
return index;
}
uint8_t bt_get_free_a2dp_stream(void)
{
uint8_t index = 0;
for(index = 0; index < NUM_STREAMS; index++){
//if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device->state == A2DP_DEV_STATE_DISCONNECTED)){
if(Is_a2dp_stream_registered(&Stream[index]) && (Stream[index].device == NULL)){
break;
}
}
return index;
}
uint8_t bt_get_free_avrcp_channel(void)
{
uint8_t index = 0;
for(index = 0; index < NUM_BT_DEVICES; index++){
if(rcpCtChannel[index].chnl.conn.state == 0){
break;
}
}
return index;
}
static void security_event_handler(const BtEvent *event)
{
//BtDeviceContext *bdc;
printf("secureity event handler %d\r\n",event->eType);
switch(event->eType) {
case BTEVENT_PIN_REQ:
SEC_SetPin(event->p.remDev, (const uint8_t *)"0000", 4, BPT_SAVE_TRUSTED);
break;
case BTEVENT_AUTHORIZATION_REQ:
SEC_Authorize(event->p.remDev, TRUE, TRUE);
break;
//case BTEVENT_PAIRING_COMPLETE:
// bdc = DS_FindDevice(&event->p.pairingInfo.remDev->bdAddr);
// break;
default:
//co_printf("SecurityEventHandler: event--0x%02x is not implemented.\r\n", event->eType);
break;
}
}
static void me_callback(const BtEvent *event)
{
LOG_INFO(NULL, "me_callback :%d,%d\r\n",event->eType,event->errCode);
switch (event->eType) {
case BTEVENT_HCI_INITIALIZED:
break;
case BTEVENT_INQUIRY_CANCELED:
break;
case BTEVENT_INQUIRY_RESULT:
printf("inq result: %x\r\n",event->p.inqResult.classOfDevice);
printf("addr:0x%02x%02x%02x%02x%02x%02x\r\n",event->p.inqResult.bdAddr.A[0],event->p.inqResult.bdAddr.A[1],event->p.inqResult.bdAddr.A[2],
event->p.inqResult.bdAddr.A[3],event->p.inqResult.bdAddr.A[4],event->p.inqResult.bdAddr.A[5]);
//printf("rssi:%d\r\n",event->p.inqResult.rssi);
break;
case BTEVENT_INQUIRY_COMPLETE:
ME_Inquiry(BT_IAC_GIAC, 5, 5);
break;
case BTEVENT_LINK_CONNECT_IND:
// if(user_bt_env.bt_connect_cb){
// user_bt_env.bt_connect_cb(BTEVENT_LINK_CONNECT_IND, &event->p.remDev->bdAddr, event->errCode);
// }
bt_connect_act_cmp(BT_EVENT_CON_IND, event->errCode, event->p.remDev);
break;
case BTEVENT_LINK_CONNECT_CNF:
// if(user_bt_env.bt_connect_cb){
// user_bt_env.bt_connect_cb(BTEVENT_LINK_CONNECT_CNF, &event->p.remDev->bdAddr, event->errCode);
// }
bt_connect_act_cmp(BT_EVENT_CON_CNF, event->errCode, event->p.remDev);
break;
case BTEVENT_LINK_DISCONNECT:
// if(user_bt_env.bt_disconnect_cb){
// user_bt_env.bt_disconnect_cb(&event->p.bdAddr, event->errCode);
// }
bt_connect_act_cmp(BT_EVENT_DISCONNECT, event->errCode, event->p.remDev);
break;
case BTEVENT_ACCESSIBLE_CHANGE:
//printf("access state = %d\r\n",event->p.aMode);
// if(user_bt_env.bt_access_change_cb){
// user_bt_env.bt_access_change_cb(event->p.aMode);
// }
bt_connect_act_cmp(BT_EVENT_ACC_CHG, event->p.aMode, NULL);
break;
case BTEVENT_MODE_CHANGE:
if(event->p.modeChange.curMode == 0){
printf("Active Mode.\r\n");
}else{
printf("Sniff Mode.\r\n");
}
break;
case BTEVENT_ROLE_CHANGE:
printf("role = %d\r\n",event->p.roleChange.newRole);
break;
case BTEVENT_HCI_COMMAND_SENT:
break;
default:
break;
}
}
static void hf_callback(HfChannel *Chan, HfCallbackParms *Info)
{
// static bool scoPacketSent = true;
if ((Info->event != HF_EVENT_AUDIO_DATA)
&& (Info->event != HF_EVENT_AUDIO_DATA_SENT)) {
printf("hf_callback: event = %d.\r\n", Info->event);
}
switch(Info->event){
case HF_EVENT_GATEWAY_FEATURES:
//printf("gw feature: %x\r\n",Info->p.features);
if(Info->p.features & HFG_FEATURE_CODEC_NEGOTIATON){
CMGR_SetAudioVoiceSettings(0x63);
}else{
CMGR_SetAudioVoiceSettings(0x60);
}
break;
case HF_EVENT_SERVICE_CONNECT_REQ:
bt_update_conn_status(BT_PROFILE_HF_CONN_REQ, Chan, Info);
break;
case HF_EVENT_SERVICE_CONNECTED:
LOG_INFO(NULL,"hf connected\r\n");
//A2DP_OpenStream(&Stream[0], &Info->p.remDev->bdAddr);
bt_update_conn_status(BT_PROFILE_HF_CONN, Chan, Info);
break;
case HF_EVENT_SERVICE_DISCONNECTED:
LOG_INFO(NULL,"hf disconnected %d\r\n",Info->errCode);
bt_update_conn_status(BT_PROFILE_HF_DISCONN, Chan, Info);
break;
case HF_EVENT_CALL_IND:
bt_update_conn_status(BT_PROFILE_HF_CALL, Chan, Info);
break;
case HF_EVENT_CALLSETUP_IND:
bt_update_conn_status(BT_PROFILE_HF_CALLSETUP, Chan, Info);
break;
case HF_EVENT_CALLHELD_IND:
break;
case HF_EVENT_RING_IND:
break;
case HF_EVENT_CALLER_ID_NOTIFY:
break;
case HF_EVENT_SPEAKER_VOLUME:
bt_update_conn_status(BT_PROFILE_HF_SPK_VOL, Chan, Info);
break;
case HF_EVENT_CURRENT_CALL_STATE:
bt_update_conn_status(BT_PROFILE_HF_CURRENT_CALL, Chan, Info);
break;
case HF_EVENT_AT_RESULT_DATA:
bt_update_conn_status(BT_PROFILE_HF_AT_RESULT, Chan, Info);
break;
case HF_EVENT_AUDIO_CONNECTED:
if (btdm_cb) {
struct app_btdm_event_t event;
event.event = APP_BTDM_EVT_SCO_CREATED;
event.param.sco_codec.hf_channel = Chan;
#if HF_CODEC_NEG == XA_ENABLED
if (Chan->codecID == 2) {
event.param.sco_codec.codec_type = APP_BTDM_CODEC_mSBC;
CMGR_SetAudioVoiceSettings(0x63);
}
else if (Chan->codecID == 1) {
event.param.sco_codec.codec_type = APP_BTDM_CODEC_PCM;
CMGR_SetAudioVoiceSettings(0x60);
}
else {
assert(0);
}
#else
event.param.sco_codec.codec_type = APP_BTDM_CODEC_PCM;
#endif
btdm_cb(&event);
}
bt_update_conn_status(BT_PROFILE_HF_AUDIO_CONN, Chan, Info);
break;
case HF_EVENT_AUDIO_DISCONNECTED:
if (btdm_cb) {
struct app_btdm_event_t event;
event.event = APP_BTDM_EVT_SCO_REMOVED;
btdm_cb(&event);
}
bt_update_conn_status(BT_PROFILE_HF_AUDIO_DISCONN, Chan, Info);
break;
case HF_EVENT_AUDIO_DATA:
if(Info->p.audioData->len > 60) {
printf("sco receive length is %d.\r\n", Info->p.audioData->len);
break;
}
if (btdm_cb) {
struct app_btdm_event_t event;
event.event = APP_BTDM_EVT_SCO_DATA;
event.param.sco_data.valid = (Info->p.audioData->errFlags == 0);
#if HF_CODEC_NEG == XA_ENABLED
if (Chan->codecID == 2) {
event.param.sco_data.codec_type = APP_BTDM_CODEC_mSBC;
}
else
#endif
{
event.param.sco_data.codec_type = APP_BTDM_CODEC_PCM;
}
event.param.sco_data.buffer = Info->p.audioData->data;
event.param.sco_data.length = Info->p.audioData->len;
btdm_cb(&event);
}
// if (scoPacketSent) {
// scoPacketSent = false;
// memcpy(scoPacket->data, Info->p.audioData->data, Info->p.audioData->len);
// scoPacket->dataLen = Info->p.audioData->len;
// HF_SendAudioData(Chan, scoPacket);
// }
break;
case HF_EVENT_AUDIO_DATA_SENT:
// scoPacketSent = true;
btdm_free(Info->p.audioPacket->data);
btdm_free(Info->p.audioPacket);
break;
#if HF_CODEC_NEG == XA_ENABLED
case HF_EVENT_CODEC_NEGOTIATION:
{
HfCommand *cmd;
if(Info->p.codecID == 1){
//cvsd
CMGR_SetAudioVoiceSettings(0x60);
}else if(Info->p.codecID == 2){
//msbc
CMGR_SetAudioVoiceSettings(0x63);
}
BtStatus ret = BT_STATUS_NO_RESOURCES;
cmd = (HfCommand *)btdm_malloc(sizeof(HfCommand));
if(cmd != NULL){
hf_codec[0] = Info->p.codecID + '0';
hf_codec[1] = 0;
ret = HF_CodecConnectionSetup((HfChannel *)Chan, hf_codec, cmd);
}
if(ret != BT_STATUS_PENDING){
btdm_free((void *)cmd);
}
}
break;
#endif
case HF_EVENT_COMMAND_COMPLETE:
btdm_free((uint8_t *)Info->p.command);
break;
default:
break;
}
}
static void hfg_callback(HfgChannel *Chan, HfgCallbackParms *Info)
{
BtStatus status;
HfgResponse *rsp;
if ((Info->hfgEvent != HFG_EVENT_AUDIO_DATA)
&& (Info->hfgEvent != HFG_EVENT_AUDIO_DATA_SENT)) {
LOG_INFO(NULL, "hfg_callback :%d\r\n",Info->hfgEvent);
}
switch (Info->hfgEvent) {
case HFG_EVENT_HANDSFREE_FEATURES:
printf("remote hf feature: %x\r\n",Info->p.features);
// if(Info->p.features & HF_FEATURE_CODEC_NEGOTIATION){
// CMGR_SetAudioVoiceSettings(0x63);
// }else{
// CMGR_SetAudioVoiceSettings(0x60);
// }
break;
case HFG_EVENT_SERVICE_CONNECT_REQ:
//App_Report("Incoming Channel");
break;
case HFG_EVENT_SERVICE_CONNECTED:
A2DP_OpenStream(&Stream[2], &Info->p.remDev->bdAddr);
break;
case HFG_EVENT_AT_COMMAND_DATA:
for(uint8_t i = 0; i < Info->p.data->dataLen; i++)
printf("%c",Info->p.data->rawData[i]);
printf("\r\n");
rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse));
status = HFG_SendOK(Chan,rsp);
if(status != BT_STATUS_PENDING){
btdm_free((void *)rsp);
}
// if(memcmp(Info->p.data->rawData,"AT+IPHONEACCEV=1,1,9",sizeof("AT+IPHONEACCEV=1,1,9")) == 0)
// {
// status = BT_STATUS_NO_RESOURCES;
// rsp = (HfgResponse *)btdm_malloc(sizeof(HfgResponse));
// if(rsp != NULL){
// status = HFG_CreateCodecConnection(&hfg_channel[0], 1, rsp);
// }
// if(status != BT_STATUS_PENDING){
// btdm_free((void *)rsp);
// }
// printf("status = %d\r\n",status);
// }
break;
case HFG_EVENT_SUPPORTED_CODEC:
printf("hf supported codec %x\r\n",Info->p.features);
if(Info->p.features == 2){
CMGR_SetAudioVoiceSettings(0x63);
}else{
CMGR_SetAudioVoiceSettings(0x60);
}
break;
case HFG_EVENT_AUDIO_DATA:
{
#if 0
if(Info->p.audioData->len > 60) {
printf("sco receive length is %d.\r\n", Info->p.audioData->len);
break;
}
#endif
#if 0
for(uint8_t i = 0; i < Info->p.audioData->len; i++)
{
fputc(Info->p.audioData->data[i],NULL);
}
#else
// if(Info->p.audioData->len == 120){
// fputc('R',NULL);
// }else if(Info->p.audioData->len == 60){
// fputc('r',NULL);
// }
BtPacket *sco_packet;
sco_packet = btdm_malloc(sizeof(BtPacket));
memset((void *)sco_packet, 0, sizeof(BtPacket));
sco_packet->data = btdm_malloc(120);
memcpy(sco_packet->data, Info->p.audioData->data, Info->p.audioData->len);
sco_packet->dataLen = Info->p.audioData->len;
status = HF_SendAudioData(Chan, sco_packet);
if(status != BT_STATUS_PENDING){
printf("no pending:%d\r\n",status);
btdm_free((void *)sco_packet->data);
btdm_free((void *)sco_packet);
}
//if(Info->p.audioData->errFlags != 0){
// fputc('a'+Info->p.audioData->errFlags,NULL);
//}
#endif
}
break;
case HFG_EVENT_AUDIO_DATA_SENT:
//fputc('s',NULL);
btdm_free((void *)Info->p.audioPacket->data);
btdm_free((void *)Info->p.audioPacket);
break;
case HFG_EVENT_CODEC_CONNECTION_RSP:
printf("hfg codec connection rsp: %d\r\n",Info->p.features);
if(Info->p.features == 2){
CMGR_SetAudioVoiceSettings(0x63);
}else{
CMGR_SetAudioVoiceSettings(0x60);
}
HFG_CreateAudioLink(&hfg_channel[0],HFG_AR_LOCAL_USER_ACTION);
break;
case HFG_EVENT_RESPONSE_COMPLETE:
btdm_free((void *)Info->p.response);
break;
}
}
static void a2dp_callback(A2dpStream *cbStream, const A2dpCallbackParms *Parms)
{
AvdtpCodec *codec;
uint8_t *elements;
uint8_t *reqElements;
uint8_t error = A2DP_ERR_NO_ERROR;
if(Parms->event == 18) {
}
else {
LOG_INFO(NULL, "a2dp callback event=%d,%x,%x\r\n", Parms->event,Parms->error,Parms->discReason);
}
switch(Parms->event) {
case A2DP_EVENT_STREAM_OPEN_IND:
bt_update_conn_status(BT_PROFILE_A2DP_OPEN_IND, cbStream, Parms);
if (AVDTP_CODEC_TYPE_SBC == Parms->p.configReq->codec.codecType) {
codec = A2DP_GetRegisteredCodec(cbStream);
elements = codec->elements;
reqElements = Parms->p.configReq->codec.elements;
/* Check requested elements with registered elements */
if (!(reqElements[0] & (elements[0] & 0xF0))) {
error = A2DP_ERR_NOT_SUPPORTED_SAMP_FREQ;
} else if (!(reqElements[0] & (elements[0] & 0x0F))) {
error = A2DP_ERR_NOT_SUPPORTED_CHANNEL_MODE;
} else if (!(reqElements[1] & (elements[1] & 0x0C))) {
error = A2DP_ERR_NOT_SUPPORTED_SUBBANDS;
} else if (!(reqElements[1] & (elements[1] & 0x03))) {
error = A2DP_ERR_NOT_SUPPORTED_ALLOC_METHOD;
} else if (reqElements[2] < elements[2]) {
error = A2DP_ERR_NOT_SUPPORTED_MIN_BITPOOL_VALUE;
} else if (reqElements[3] > elements[3]) {
error = A2DP_ERR_NOT_SUPPORTED_MAX_BITPOOL_VALUE;
}
// codec->freq = (reqElements[0] & 0xF0) >> 5;
A2DP_OpenStreamRspWithSinkDelay(cbStream, error,
AVDTP_SRV_CAT_MEDIA_CODEC,
0);
}
else if(AVDTP_CODEC_TYPE_MPEG2_4_AAC== Parms->p.configReq->codec.codecType) {
codec = A2DP_GetRegisteredCodec(cbStream);
elements = codec->elements;
reqElements = Parms->p.configReq->codec.elements;
// if(reqElements[1] & 0x01) {
// codec->freq = 1;
// }
// else if(reqElements[2] & 0x80) {
// codec->freq = 0;
// }
A2DP_OpenStreamRspWithSinkDelay(cbStream, error,
AVDTP_SRV_CAT_MEDIA_CODEC,
0);
}
else {
/* Refuse to accept incoming con to MP3 stream for now */
A2DP_OpenStreamRspWithSinkDelay(cbStream,
AVRCP_ERR_UNKNOWN_ERROR,
AVDTP_SRV_CAT_MEDIA_CODEC,
0);
}
break;
case A2DP_EVENT_CODEC_INFO:
/* Found a matching codec */
codec = A2DP_GetRegisteredCodec(cbStream);
elements = codec->elements;
/* Save the remote codec information. Selection
* of capabilities will be made from the UI.
*/
cfgCodec.codecType = Parms->p.codec->codecType;
cfgCodec.elemLen = Parms->p.codec->elemLen;
cfgCodec.elements = cfgElements;
if (cfgCodec.codecType == AVDTP_CODEC_TYPE_SBC) {
/* Only the matching codec information
* elements can be selected.
*/
cfgCodec.elements[0]
= (uint8_t)(Parms->p.codec->elements[0] & elements[0]);
cfgCodec.elements[1]
= (uint8_t)(Parms->p.codec->elements[1] & elements[1]);
cfgCodec.elements[2]
= (uint8_t)(max(Parms->p.codec->elements[2], elements[2]));
cfgCodec.elements[3]
= (uint8_t)(min(Parms->p.codec->elements[3], elements[3]));
}
break;
case A2DP_EVENT_GET_CONFIG_IND:
LOG_INFO(NULL, "codec type=%d,%x,%x,%x,%x\r\n",cfgCodec.codecType,cfgCodec.elements[0],cfgCodec.elements[1],cfgCodec.elements[2],cfgCodec.elements[3]);
/* Make sure something valid is configured for each field */
if (cfgCodec.codecType == AVDTP_CODEC_TYPE_SBC) {
if ( (cfgCodec.elements[0] & 0xF0)
&& (cfgCodec.elements[0] & 0x0F)
&& (cfgCodec.elements[1] & 0xF0)
&& (cfgCodec.elements[1] & 0x0C)
&& (cfgCodec.elements[1] & 0x03)) {
/* Pick the sampling rate supported */
if (cfgCodec.elements[0] & 0x80) {
cfgCodec.elements[0] &= 0x8F;
} else if (cfgCodec.elements[0] & 0x40) {
cfgCodec.elements[0] &= 0x4F;
} else if (cfgCodec.elements[0] & 0x20) {
cfgCodec.elements[0] &= 0x2F;
} else if (cfgCodec.elements[0] & 0x10) {
cfgCodec.elements[0] &= 0x1F;
}
/* Pick the channel mode */
if (cfgCodec.elements[0] & 0x08) {
cfgCodec.elements[0] &= 0xF8;
} else if (cfgCodec.elements[0] & 0x04) {
cfgCodec.elements[0] &= 0xF4;
} else if (cfgCodec.elements[0] & 0x02) {
cfgCodec.elements[0] &= 0xF2;
} else if (cfgCodec.elements[0] & 0x01) {
cfgCodec.elements[0] &= 0xF1;
}
/* Pick the block length */
if (cfgCodec.elements[1] & 0x80) {
cfgCodec.elements[1] &= 0x8F;
} else if (cfgCodec.elements[1] & 0x40) {
cfgCodec.elements[1] &= 0x4F;
} else if (cfgCodec.elements[1] & 0x20) {
cfgCodec.elements[1] &= 0x2F;
} else if (cfgCodec.elements[1] & 0x10) {
cfgCodec.elements[1] &= 0x1F;
}
/* Pick the number of subbands */
if (cfgCodec.elements[1] & 0x08) {
cfgCodec.elements[1] &= 0xFB;
} else if (cfgCodec.elements[1] & 0x04) {
cfgCodec.elements[1] &= 0xF7;
}
/* Pick the allocation method */
if (cfgCodec.elements[1] & 0x02) {
cfgCodec.elements[1] &= 0xFE;
} else if (cfgCodec.elements[1] & 0x01) {
cfgCodec.elements[1] &= 0xFD;
}
/* Select Min/Max Bitpools */
cfgCodec.elements[2] = cfgCodec.elements[2];
cfgCodec.elements[3] = cfgCodec.elements[3];
A2DP_SetStreamConfigWithSinkDelay(cbStream, &cfgCodec, 0, 0);
}
else{
A2DP_CloseStream(cbStream);
}
}
break;
case A2DP_EVENT_STREAM_OPEN:
LOG_INFO(NULL,"a2dp connected\r\n");
bt_update_conn_status(BT_PROFILE_A2DP_CONN, cbStream, Parms);
break;
case A2DP_EVENT_STREAM_START_IND:
A2DP_StartStreamRsp(cbStream, A2DP_ERR_NO_ERROR);
break;
case A2DP_EVENT_STREAM_STARTED:
if (btdm_cb) {
struct app_btdm_event_t event;
event.event = APP_BTDM_EVT_A2DP_STREAM_STARTED;
codec = A2DP_GetRegisteredCodec(cbStream);
if (codec->codecType == AVDTP_CODEC_TYPE_MPEG2_4_AAC) {
event.param.a2dp_codec.codec_type = APP_BTDM_CODEC_AAC;
if (codec->elements[1] & A2DP_AAC_CODEC_FREQ_44100) {
event.param.a2dp_codec.sample_rate = 44100;
}
else if (codec->elements[2] & A2DP_AAC_CODEC_FREQ_48000) {
event.param.a2dp_codec.sample_rate = 48000;
}
else {
assert(0);
}
}
else if (codec->codecType == AVDTP_CODEC_TYPE_SBC) {
event.param.a2dp_codec.codec_type = APP_BTDM_CODEC_SBC;
if (codec->elements[0] & A2DP_SBC_CODEC_FREQ_44100) {
event.param.a2dp_codec.sample_rate = 44100;
}
else if (codec->elements[0] & A2DP_SBC_CODEC_FREQ_48000) {
event.param.a2dp_codec.sample_rate = 48000;
}
else {
assert(0);
}
}
else {
event.param.a2dp_codec.codec_type = APP_BTDM_CODEC_UNKNOWN;
}
btdm_cb(&event);
}
bt_update_conn_status(BT_PROFILE_A2DP_PLAYING, cbStream, Parms);
break;
case A2DP_EVENT_STREAM_SUSPENDED:
if (btdm_cb) {
struct app_btdm_event_t event;
event.event = APP_BTDM_EVT_A2DP_STREAM_STOPPED;
btdm_cb(&event);
}
bt_update_conn_status(BT_PROFILE_A2DP_SUSPEND, cbStream, Parms);
break;
case A2DP_EVENT_STREAM_CLOSED:
if (btdm_cb) {
struct app_btdm_event_t event;
event.event = APP_BTDM_EVT_A2DP_STREAM_STOPPED;
btdm_cb(&event);
}
bt_update_conn_status(BT_PROFILE_A2DP_DISCONN, cbStream, Parms);
break;
case A2DP_EVENT_STREAM_DATA_IND:
if (btdm_cb) {
struct app_btdm_event_t event;
event.event = APP_BTDM_EVT_A2DP_STREAM_DATA;
event.param.a2dp_data.buffer = Parms->p.data + 13;
event.param.a2dp_data.length = Parms->len - 13;
btdm_cb(&event);
}
break;
default:
break;
}
}
static void avrcp_callback(AvrcpChannel *chnl, const AvrcpCallbackParms *Parms)
{
AvrcpAdvancedPdu *avrcp_cmd;
BtStatus status;
LOG_INFO(NULL, "avrcp callback event=%d, status=%d, chnl=%x\r\n",Parms->event, Parms->status, chnl);
switch (Parms->event) {
case AVRCP_EVENT_CONNECT_IND:
AVRCP_ConnectRsp(chnl,TRUE);
break;
case AVRCP_EVENT_CONNECT:
{
avrcp_cmd = btdm_malloc(sizeof(AvrcpAdvancedPdu));
avrcp_cmd->parms = (uint8_t *)btdm_malloc(64);
status = AVRCP_CtGetCapabilities((AvrcpChannel *)chnl, avrcp_cmd, AVRCP_CAPABILITY_EVENTS_SUPPORTED);
if (status != BT_STATUS_PENDING) {
btdm_free(avrcp_cmd->parms);
btdm_free(avrcp_cmd);
}
AVRCP_TgSetEventMask(chnl,AVRCP_ENABLE_VOLUME_CHANGED);
}
LOG_INFO(NULL, "avrcp connected\r\n");
bt_update_conn_status(BT_PROFILE_AVRCP_CONN, chnl, Parms);
break;
case AVRCP_EVENT_DISCONNECT:
LOG_INFO(NULL, "avrcp disconnected\r\n");
bt_update_conn_status(BT_PROFILE_AVRCP_DISCONN, chnl, Parms);
break;
case AVRCP_EVENT_ADV_INFO:
if(Parms->advOp == AVRCP_OP_SET_ABSOLUTE_VOLUME) {
//LOG_INFO("SET_ABSOLUTE_VOLUME is %d.\r\n", event->param.adv.info.volume);
printf("+VOL:%02x\r\n",Parms->p.adv.info.volume);
}
break;
case AVRCP_EVENT_ADV_RESPONSE:
///本地查询TG支持事件返回消<E59B9E><E6B688>?
/**/
if((Parms->advOp == AVRCP_OP_GET_CAPABILITIES)
&&(Parms->p.adv.rsp.capability.type == AVRCP_CAPABILITY_EVENTS_SUPPORTED)){
//printf("cap eventmaskk = %x\r\n",event->param.adv.rsp.capability.info.eventMask);
if(Parms->p.adv.rsp.capability.info.eventMask & AVRCP_ENABLE_PLAY_STATUS_CHANGED){
///注册播放状态改变事件当TG播放状态改变时产生AVRCP_EVENT_ADV_NOTIFY事件
avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu));
avrcp_cmd->parms = (uint8_t *)btdm_malloc(64);
status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_MEDIA_STATUS_CHANGED, 0);
if (status != BT_STATUS_PENDING) {
btdm_free(avrcp_cmd->parms);
btdm_free(avrcp_cmd);
}
}
if(Parms->p.adv.rsp.capability.info.eventMask & AVRCP_ENABLE_TRACK_CHANGED){
///注册歌曲改变事件当TG播放状态改变时产生AVRCP_EVENT_ADV_NOTIFY事件
avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu));
avrcp_cmd->parms = (uint8_t *)btdm_malloc(64);
status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_TRACK_CHANGED, 0);
if (status != BT_STATUS_PENDING) {
btdm_free(avrcp_cmd->parms);
btdm_free(avrcp_cmd);
}
}
}
///本地注册事件返回的当前状<E5898D><E78AB6>?
if(Parms->advOp == AVRCP_OP_REGISTER_NOTIFY) {
///播放状态改变通知的当前状<E5898D><E78AB6>?
if(Parms->p.adv.notify.event == AVRCP_EID_MEDIA_STATUS_CHANGED) {
}
else if(Parms->p.adv.notify.event == AVRCP_EID_TRACK_CHANGED){
//user_bt_get_media_info();
}
}
if(Parms->advOp == AVRCP_OP_GET_MEDIA_INFO){
uint16_t len0 = Parms->p.adv.rsp.element.txt[0].length;
uint16_t len1 = Parms->p.adv.rsp.element.txt[1].length;
printf("media info: %d,%s,%d\r\n",len0,Parms->p.adv.rsp.element.txt[0].string,len1);
}
if(Parms->advOp == AVRCP_OP_GET_PLAY_STATUS){
printf("media length:%d,pos:%d,status:%d\r\n",Parms->p.adv.rsp.playStatus.length,Parms->p.adv.rsp.playStatus.position,Parms->p.adv.rsp.playStatus.mediaStatus);
}
break;
case AVRCP_EVENT_PANEL_CNF:
if(Parms->p.panelCnf.press == TRUE){
switch(Parms->p.panelCnf.operation) {
case AVRCP_POP_PAUSE:
AVRCP_SetPanelKey(chnl, AVRCP_POP_PAUSE, FALSE);
break;
case AVRCP_POP_PLAY:
AVRCP_SetPanelKey(chnl, AVRCP_POP_PLAY, FALSE);
break;
case AVRCP_POP_FORWARD:
AVRCP_SetPanelKey(chnl, AVRCP_POP_FORWARD, FALSE);
break;
case AVRCP_POP_BACKWARD:
AVRCP_SetPanelKey(chnl, AVRCP_POP_BACKWARD, FALSE);
break;
case AVRCP_POP_STOP:
AVRCP_SetPanelKey(chnl, AVRCP_POP_STOP, FALSE);
break;
}
}
break;
case AVRCP_EVENT_ADV_NOTIFY:
{
const AvrcpAdvNotifyParms *avrcp_ntf = &Parms->p.adv.notify;
if(Parms->errorCode == AVRCP_ERR_NO_ERROR) {
switch(avrcp_ntf->event) {
case AVRCP_EID_TRACK_CHANGED:
{
avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu));
avrcp_cmd->parms = (uint8_t *)btdm_malloc(64);
status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_TRACK_CHANGED, 0);
if (status != BT_STATUS_PENDING) {
btdm_free(avrcp_cmd->parms);
btdm_free(avrcp_cmd);
}
}
break;
case AVRCP_EID_MEDIA_STATUS_CHANGED:
{
///重新注册播放状态改变通知消息
uint8_t media_status = Parms->p.adv.notify.p.mediaStatus;
bt_update_conn_status(BT_PROFILE_AVRCP_MEDIA_STATUS, chnl, &media_status);
avrcp_cmd = (AvrcpAdvancedPdu *)btdm_malloc(sizeof(AvrcpAdvancedPdu));
avrcp_cmd->parms = (uint8_t *)btdm_malloc(64);
status = AVRCP_CtRegisterNotification(chnl, avrcp_cmd, AVRCP_EID_MEDIA_STATUS_CHANGED, 0);
if (status != BT_STATUS_PENDING) {
btdm_free(avrcp_cmd->parms);
btdm_free(avrcp_cmd);
}
}
break;
}
}
}
break;
case AVRCP_EVENT_ADV_TX_DONE:
btdm_free(Parms->p.adv.txPdu->parms);
btdm_free(Parms->p.adv.txPdu);
break;
default:
break;
}
}
static void pbap_callback(PbapClientCallbackParms *Parms)
{
printf("pbap callback event = %d\r\n",Parms->event);
switch (Parms->event) {
case PBAP_EVENT_PARAMS_RX:
{
if ((Parms->oper == PBAPOP_PULL_PHONEBOOK) ||
(Parms->oper == PBAPOP_PULL_VCARD_LISTING)) {
printf("miss calls: %d,pb size=%d\r\n",Parms->u.paramsRx.newMissedCalls,Parms->u.paramsRx.phonebookSize);
}
}
break;
case PBAP_EVENT_DATA_IND:
bt_update_conn_status(BT_PROFILE_PBAP_DATA_IND, NULL, Parms);
break;
case PBAP_EVENT_TP_CONNECTED:
bt_update_conn_status(BT_PROFILE_PBAP_CONN, NULL, Parms);
break;
case PBAP_EVENT_TP_DISCONNECTED:
bt_update_conn_status(BT_PROFILE_PBAP_DISCONN, NULL, Parms);
break;
case PBAP_EVENT_CONTINUE:
/* Always call continue to keep the commands flowing */
PBAP_ClientContinue(Parms->client);
break;
case PBAP_EVENT_ABORTED:
/* The requested operation was aborted. */
break;
case PBAP_EVENT_COMPLETE:
bt_update_conn_status(BT_PROFILE_PBAP_COMP, NULL, Parms);
break;
default:
break;
}
}
void spp_callback(SppDev *locDev, SppCallbackParms *Info)
{
printf("spp callback, event = %d\r\n",Info->event);
switch(Info->event) {
case SPP_EVENT_REMDEV_CONNECTED:
printf("spp connected\r\n");
break;
case SPP_EVENT_REMDEV_DISCONNECTED:
printf("spp disconnected\r\n");
break;
case SPP_EVENT_DATA_IND:
printf("spp recv: ");
for(uint8_t i = 0; i < Info->p.pkt->dataLen; i++)
{
printf("%c",Info->p.pkt->data[i]);
}
printf("\r\n");
break;
case SPP_EVENT_SEND_COMPLETE:
btdm_free(Info->p.pkt->data);
btdm_free((uint8_t *)Info->p.pkt);
break;
}
}
//void a2dp_device_callback(void *Device, const void *Parms)
//{
// switch(*(volatile uint8_t *)Parms){
// case 1/*AVDEV_EVENT_AVDTP_CONNECT_IND*/:
// AVDEV_SignalConnectRsp(Device, TRUE, a2dp_device_callback);
// break;
// default:
// break;
// }
//}
void app_btdm_struct_size_dump(void)
{
printf("BTDM STRUCT SIZE: defined in stack.\r\n");
extern void btdm_struct_size_dump(void);
btdm_struct_size_dump();
printf("BTDM STRUCT SIZE: defined in api.\r\n");
printf("BtEvent is %d\r\n", sizeof(BtEvent));
printf("BtRemoteDevice is %d\r\n", sizeof(BtRemoteDevice));
printf("RfDeferEvent is %d\r\n", sizeof(RfDeferEvent));
printf("RfChannel is %d\r\n", sizeof(RfChannel));
printf("HfChannel is %d\r\n", sizeof(HfChannel));
printf("HfCommand is %d\r\n", sizeof(HfCommand));
printf("HfCallbackParms is %d\r\n", sizeof(HfCallbackParms));
printf("HfgChannel is %d\r\n", sizeof(HfgChannel));
printf("HfgCallbackParms is %d\r\n", sizeof(HfgCallbackParms));
printf("A2dpStream is %d\r\n", sizeof(A2dpStream));
printf("A2dpCallbackParms is %d\r\n", sizeof(A2dpCallbackParms));
printf("AvdtpStream is %d\r\n", sizeof(AvdtpStream));
printf("AvdtpConn is %d\r\n", sizeof(AvdtpConn));
printf("AvdtpCallbackParms is %d\r\n", sizeof(AvdtpCallbackParms));
printf("AvctpCallbackParms is %d\r\n", sizeof(AvctpCallbackParms));
printf("AvctpChannel is %d\r\n", sizeof(AvctpChannel));
printf("AvctpCmdFrame is %d\r\n", sizeof(AvctpCmdFrame));
printf("AvctpRspFrame is %d\r\n", sizeof(AvctpRspFrame));
printf("AvrcpChannel is %d\r\n", sizeof(AvrcpChannel));
printf("AvrcpCallbackParms is %d\r\n", sizeof(AvrcpCallbackParms));
printf("AvrcpAdvancedPdu is %d\r\n", sizeof(AvrcpAdvancedPdu));
printf("AvrcpPlayerSetting is %d\r\n", sizeof(AvrcpPlayerSetting));
printf("AvrcpPlayerStrings is %d\r\n", sizeof(AvrcpPlayerStrings));
printf("AvrcpEqString is %d\r\n", sizeof(AvrcpEqString));
printf("AvrcpRepeatString is %d\r\n", sizeof(AvrcpRepeatString));
printf("AvrcpShuffleString is %d\r\n", sizeof(AvrcpShuffleString));
printf("AvrcpScanString is %d\r\n", sizeof(AvrcpScanString));
printf("AvrcpExtString is %d\r\n", sizeof(AvrcpExtString));
printf("AvrcpCharSets is %d\r\n", sizeof(AvrcpCharSets));
printf("AvrcpMediaInfo is %d\r\n", sizeof(AvrcpMediaInfo));
printf("AvrcpMediaPlayStatus is %d\r\n", sizeof(AvrcpMediaPlayStatus));
printf("AvrcpTrackStruct is %d\r\n", sizeof(AvrcpTrackStruct));
}
void app_bt_send_sco_data(void *channel, uint8_t seq, uint8_t *data, uint16_t length)
{
BtPacket *sco_packet;
HfChannel *Chan = channel;
uint16_t data_length;
uint8_t sub_seq = 0;
sco_packet = btdm_malloc(sizeof(BtPacket));
if (sco_packet) {
memset((void *)sco_packet, 0, sizeof(BtPacket));
if (length == 57) {
data_length = 60;
sco_packet->data = btdm_malloc(data_length);
sco_packet->data[0] = 0x01;
if (seq & 0x01) {
sub_seq = 0x30;
}
if (seq & 0x02) {
sub_seq |= 0xc0;
}
sco_packet->data[1] = 0x08 | sub_seq;
memcpy(&sco_packet->data[2], data, length);
sco_packet->data[59] = 0x00;
sco_packet->dataLen = data_length;
}
else {
sco_packet->data = btdm_malloc(length);
memcpy(sco_packet->data, data, length);
sco_packet->dataLen = length;
}
HF_SendAudioData(Chan, sco_packet);
}
}
void app_bt_init(app_btdm_callback_t cb)
{
// app_btdm_struct_size_dump();
#define EIR_DATA_SIZE 50
uint8_t eir_data[EIR_DATA_SIZE];
uint8_t index = 0;
uint8_t rand_num[4];
uint8_t hex_2_char[] = {'0', '1', '2','3', '4', '5','6', '7', '8','9', 'a', 'b','c', 'd', 'e', 'f'};
btdm_cb = cb;
#if BTDM_STACK_ENABLE_HF
hf_channel = btdm_malloc(sizeof(HfChannel) * NUM_BT_DEVICES);
#endif
#if BTDM_STACK_ENABLE_AG
hfg_channel = btdm_malloc(sizeof(HfgChannel) * NUM_BT_DEVICES);
#endif
Stream = btdm_malloc(sizeof(A2dpStream) * NUM_STREAMS);
#if BTDM_STACK_ENABLE_AVRCP
rcpCtChannel = btdm_malloc(sizeof(AvrcpChannel) * NUM_BT_DEVICES);
rcpTgChannel = btdm_malloc(sizeof(AvrcpChannel) * NUM_BT_DEVICES);
#endif
#if BTDM_STACK_ENABLE_PBAP
pbap_client = btdm_malloc(sizeof(PbapClientSession) * NUM_BT_DEVICES);
#endif
#if BTDM_STACK_ENABLE_SPP
spp_dev = btdm_malloc(sizeof(SppDev) * NUM_BT_DEVICES);
#endif
// scoPacket = btdm_malloc(sizeof(BtPacket));
// memset((void *)scoPacket, 0, sizeof(BtPacket));
// scoPacket->data = btdm_malloc(120);
ME_InitHandler(&securityHandler);
securityHandler.callback = security_event_handler;
SEC_RegisterPairingHandler(&securityHandler);
SEC_RegisterAuthorizeHandler(&securityHandler);
/* Set our promiscuous link policies */
ME_SetDefaultLinkPolicy(((BLP_MASTER_SLAVE_SWITCH|BLP_SNIFF_MODE)&(~BLP_MASK)),
((BLP_MASTER_SLAVE_SWITCH|BLP_SNIFF_MODE)&(~BLP_MASK)));
#if BT_ADDR_RANDOM_ENABLE
if(flashdb_get(FDB_KEY_USER_RANDOM_SEED, (void *)&rand_num[0], 4) != 0){
default_name[7] = hex_2_char[(rand_num[1]&0xf0) >> 4];
default_name[8] = hex_2_char[(rand_num[1]&0x0f)];
default_name[9] = hex_2_char[(rand_num[0]&0xf0) >> 4];
default_name[10] = hex_2_char[(rand_num[0]&0x0f)];
}
#endif
ME_SetLocalDeviceName((const uint8_t *)default_name, sizeof(default_name));
memset(&eir_data[0],0,EIR_DATA_SIZE);
eir_data[index++] = sizeof(default_name) + 1;
eir_data[index++] = 0x09;
memcpy(&(eir_data[index]),default_name,sizeof(default_name));
ME_SetExtInquiryRsp(0x01,eir_data,sizeof(default_name)+1);
SEC_SetBondingMode(GENERAL_BONDING);
SEC_SetIoCapabilities(IO_NO_IO);
ME_InitHandler(&(globalHandler));
globalHandler.callback = me_callback;
ME_RegisterGlobalHandler(&globalHandler);
// ME_SetEventMask(&globalHandler, (BEM_ACCESSIBLE_CHANGE |
// BEM_LINK_CONNECT_CNF |
// BEM_LINK_CONNECT_IND |
// BEM_LINK_DISCONNECT |
// BEM_ROLE_CHANGE |
// BEM_MODE_CHANGE |
// BEM_INQUIRY_COMPLETE |
// BEM_INQUIRY_RESULT |
// BEM_INQUIRY_CANCELED));
ME_SetEventMask(&globalHandler, BEM_ALL_EVENTS);
secParms.level = (BSL_SECURITY_L2_IN | BSL_SECURITY_L2_OUT);//HF_SECURITY_SETTINGS;
secParms.pinLen = 4;
#if BTDM_STACK_ENABLE_HF
HF_SetSupportedFeature(HF_SDK_FEATURES);
for (uint8_t i=0; i<NUM_BT_DEVICES; i++) {
HF_RegisterSec(&hf_channel[i], hf_callback, &secParms);
}
#endif
ME_SetClassOfDevice( COD_AUDIO
| COD_MAJOR_AUDIO
| COD_MINOR_AUDIO_HANDSFREE);
#if BTDM_STACK_ENABLE_AG
HFG_SetSupportedFeature(HFG_SDK_FEATURES);
for (uint8_t i=0; i<NUM_BT_DEVICES; i++) {
HFG_RegisterSec(&hfg_channel[i], hfg_callback, &secParms);
}
#endif
#if BTDM_STACK_ENABLE_A2DP_SNK
/* Register SBC stream sink */
sbcSnkCodec1.codecType = AVDTP_CODEC_TYPE_SBC;
sbcSnkCodec1.elemLen = sizeof(SbcSnkElements);
sbcSnkCodec1.elements = SbcSnkElements;
#if BTDM_STACK_ENABLE_AAC
aacSnkCodec1.codecType = AVDTP_CODEC_TYPE_MPEG2_4_AAC;
aacSnkCodec1.elemLen = sizeof(AacSnkElements);
aacSnkCodec1.elements = AacSnkElements;
#else
sbcSnkCodec2.codecType = AVDTP_CODEC_TYPE_SBC;
sbcSnkCodec2.elemLen = sizeof(SbcSnkElements);
sbcSnkCodec2.elements = SbcSnkElements;
#endif
Stream[0].type = A2DP_STREAM_TYPE_SINK;
Stream[1].type = A2DP_STREAM_TYPE_SINK;
A2DP_Register(&Stream[0], &sbcSnkCodec1, a2dp_callback);
#if BTDM_STACK_ENABLE_AAC
A2DP_Register(&Stream[1], &aacSnkCodec1, a2dp_callback);
#else
A2DP_Register(&Stream[1], &sbcSnkCodec2, a2dp_callback);
#endif
#endif
#if BTDM_STACK_ENABLE_A2DP_SRC
/* Register SBC stream src */
sbcSrcCodec1.codecType = AVDTP_CODEC_TYPE_SBC;
sbcSrcCodec1.elemLen = sizeof(SbcSrcElements);
sbcSrcCodec1.elements = SbcSrcElements;
Stream[2].type = A2DP_STREAM_TYPE_SOURCE;
Stream[3].type = A2DP_STREAM_TYPE_SOURCE;
A2DP_Register(&Stream[2], &sbcSrcCodec1, a2dp_callback);
A2DP_Register(&Stream[3], &sbcSrcCodec1, a2dp_callback);
#endif
// AVDEV_ListenSignalLink(a2dp_device_callback);
#if BTDM_STACK_ENABLE_AVRCP || BTDM_STACK_ENABLE_A2DP_SNK || BTDM_STACK_ENABLE_A2DP_SRC
for (uint8_t i=0; i<NUM_BT_DEVICES; i++) {
AVRCP_RegisterSec(&rcpCtChannel[i], avrcp_callback, AVRCP_CT, &secParms);
#if AVRCP_ADVANCED_TARGET == XA_ENABLED
AVRCP_TgSetEventMask(&rcpCtChannel[i], AVRCP_ENABLE_VOLUME_CHANGED);
#endif
AVRCP_RegisterSec(&rcpTgChannel[i], avrcp_callback, AVRCP_TG, &secParms);
}
#endif
#if BTDM_STACK_ENABLE_PBAP
for (uint8_t i=0; i<NUM_BT_DEVICES; i++) {
PBAP_RegisterClientSec(&pbap_client[i], pbap_callback, &secParms);
}
#endif
#if BTDM_STACK_ENABLE_SPP
for (uint8_t i=0; i<NUM_BT_DEVICES; i++) {
spp_register(&spp_dev[i], &secParms, SPP_SERVER_PORT, spp_callback);
}
#endif
ME_SetAccessibleModeC(BAM_NOT_ACCESSIBLE, &access_mode_nc);
ME_SetAccessibleModeNC(BAM_GENERAL_ACCESSIBLE, &access_mode_nc);
}