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

1285 lines
48 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.

#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);
}