/****************************************************************************** * Copyright (c) 2016, The Linux Foundation. All rights reserved. * * Not a contribution. ******************************************************************************/ /****************************************************************************** * * Copyright (C) 2004-2012 Broadcom Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * * This is the advanced audio/video call-out function implementation for * BTIF. * ******************************************************************************/ #include "string.h" #include "a2d_api.h" #include "a2d_sbc.h" #include "bta_sys.h" #include "bta_av_api.h" #include "bta_av_co.h" #include "bta_av_ci.h" #include "bta_av_sbc.h" #include "btif_media.h" #include "sbc_encoder.h" #include "btif_av.h" #include "btif_av_co.h" #include "btif_util.h" #include "osi/include/mutex.h" #include "bt_utils.h" #include "a2d_aptx.h" #include "a2d_aptx_hd.h" #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) #include "a2d_aac.h" #include "bta_av_aac.h" #endif /***************************************************************************** ** Constants *****************************************************************************/ #define FUNC_TRACE() APPL_TRACE_DEBUG("%s", __FUNCTION__); /* Macro to retrieve the number of elements in a statically allocated array */ #define BTA_AV_CO_NUM_ELEMENTS(__a) (sizeof(__a)/sizeof((__a)[0])) /* MIN and MAX macros */ #define BTA_AV_CO_MIN(X,Y) ((X) < (Y) ? (X) : (Y)) #define BTA_AV_CO_MAX(X,Y) ((X) > (Y) ? (X) : (Y)) /* Macro to convert audio handle to index and vice versa */ #define BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl) (((hndl) & (~BTA_AV_CHNL_MSK)) - 1) #define BTA_AV_CO_AUDIO_INDX_TO_HNDL(indx) (((indx) + 1) | BTA_AV_CHNL_AUDIO) /* Offsets to access codec information in SBC codec */ #define BTA_AV_CO_SBC_FREQ_CHAN_OFF 3 #define BTA_AV_CO_SBC_BLOCK_BAND_OFF 4 #define BTA_AV_CO_SBC_MIN_BITPOOL_OFF 5 #define BTA_AV_CO_SBC_MAX_BITPOOL_OFF 6 #ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ #define BTA_AV_CO_SBC_MAX_BITPOOL 51 #else #define BTA_AV_CO_SBC_MAX_BITPOOL 53 #endif /* SCMS-T protect info */ const UINT8 bta_av_co_cp_scmst[BTA_AV_CP_INFO_LEN] = "\x02\x02\x00"; /* SBC SRC codec capabilities */ const tA2D_SBC_CIE bta_av_co_sbc_caps = { #ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ (A2D_SBC_IE_SAMP_FREQ_48), /* samp_freq */ #else (A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ #endif (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */ (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */ (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */ (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */ BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */ A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ }; /* SBC SINK codec capabilities */ const tA2D_SBC_CIE bta_av_co_sbc_sink_caps = { (A2D_SBC_IE_SAMP_FREQ_48 | A2D_SBC_IE_SAMP_FREQ_44), /* samp_freq */ (A2D_SBC_IE_CH_MD_MONO | A2D_SBC_IE_CH_MD_STEREO | A2D_SBC_IE_CH_MD_JOINT | A2D_SBC_IE_CH_MD_DUAL), /* ch_mode */ (A2D_SBC_IE_BLOCKS_16 | A2D_SBC_IE_BLOCKS_12 | A2D_SBC_IE_BLOCKS_8 | A2D_SBC_IE_BLOCKS_4), /* block_len */ (A2D_SBC_IE_SUBBAND_4 | A2D_SBC_IE_SUBBAND_8), /* num_subbands */ (A2D_SBC_IE_ALLOC_MD_L | A2D_SBC_IE_ALLOC_MD_S), /* alloc_mthd */ A2D_SBC_IE_MAX_BITPOOL, /* max_bitpool */ A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ }; #if !defined(BTIF_AV_SBC_DEFAULT_SAMP_FREQ) #ifdef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ #define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_48 #else #define BTIF_AV_SBC_DEFAULT_SAMP_FREQ A2D_SBC_IE_SAMP_FREQ_44 #endif #endif /* A2dp offload capabilities */ #define SBC 0 #define APTX 1 #define AAC 2 #define APTXHD 3 /* Default SBC codec configuration */ const tA2D_SBC_CIE btif_av_sbc_default_config = { BTIF_AV_SBC_DEFAULT_SAMP_FREQ, /* samp_freq */ A2D_SBC_IE_CH_MD_JOINT, /* ch_mode */ A2D_SBC_IE_BLOCKS_16, /* block_len */ A2D_SBC_IE_SUBBAND_8, /* num_subbands */ A2D_SBC_IE_ALLOC_MD_L, /* alloc_mthd */ BTA_AV_CO_SBC_MAX_BITPOOL, /* max_bitpool */ A2D_SBC_IE_MIN_BITPOOL /* min_bitpool */ }; const tA2D_APTX_CIE bta_av_co_aptx_caps = { A2D_APTX_VENDOR_ID, A2D_APTX_CODEC_ID_BLUETOOTH, #ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ A2D_APTX_SAMPLERATE_44100, #else A2D_APTX_SAMPLERATE_48000, #endif A2D_APTX_CHANNELS_STEREO, A2D_APTX_FUTURE_1, A2D_APTX_FUTURE_2 }; /* Default aptX codec configuration */ const tA2D_APTX_CIE btif_av_aptx_default_config = { A2D_APTX_VENDOR_ID, A2D_APTX_CODEC_ID_BLUETOOTH, #ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ A2D_APTX_SAMPLERATE_44100, #else A2D_APTX_SAMPLERATE_48000, #endif A2D_APTX_CHANNELS_STEREO, A2D_APTX_FUTURE_1, A2D_APTX_FUTURE_2 }; const tA2D_APTX_HD_CIE bta_av_co_aptx_hd_caps = { A2D_APTX_HD_VENDOR_ID, A2D_APTX_HD_CODEC_ID_BLUETOOTH, #ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ A2D_APTX_HD_SAMPLERATE_44100, #else A2D_APTX_HD_SAMPLERATE_48000, #endif A2D_APTX_HD_CHANNELS_STEREO, A2D_APTX_HD_ACL_SPRINT_RESERVED0, A2D_APTX_HD_ACL_SPRINT_RESERVED1, A2D_APTX_HD_ACL_SPRINT_RESERVED2, A2D_APTX_HD_ACL_SPRINT_RESERVED3 }; /* Default aptX_hd codec configuration */ const tA2D_APTX_HD_CIE btif_av_aptx_hd_default_config = { A2D_APTX_HD_VENDOR_ID, A2D_APTX_HD_CODEC_ID_BLUETOOTH, #ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ A2D_APTX_HD_SAMPLERATE_44100, #else A2D_APTX_HD_SAMPLERATE_48000, #endif A2D_APTX_HD_CHANNELS_STEREO, A2D_APTX_HD_ACL_SPRINT_RESERVED0, A2D_APTX_HD_ACL_SPRINT_RESERVED1, A2D_APTX_HD_ACL_SPRINT_RESERVED2, A2D_APTX_HD_ACL_SPRINT_RESERVED3 }; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) const tA2D_AAC_CIE bta_av_co_aac_caps = { (A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC|A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LC), /* obj type */ #ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ (A2D_AAC_IE_SAMP_FREQ_44100), #else (A2D_AAC_IE_SAMP_FREQ_44100 | A2D_AAC_IE_SAMP_FREQ_48000), #endif (A2D_AAC_IE_CHANNELS_1 | A2D_AAC_IE_CHANNELS_2 ), /* channels */ A2D_AAC_IE_BIT_RATE, /* BIT RATE */ A2D_AAC_IE_VBR_NOT_SUPP /* variable bit rate */ }; /* Default AAC codec configuration */ const tA2D_AAC_CIE btif_av_aac_default_config = { A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC, /* obj type */ #ifndef BTA_AV_SPLIT_A2DP_DEF_FREQ_48KHZ A2D_AAC_IE_SAMP_FREQ_44100, /* samp_freq */ #else A2D_AAC_IE_SAMP_FREQ_48000, /* samp_freq */ #endif A2D_AAC_IE_CHANNELS_2, /* channels */ BTIF_AAC_DEFAULT_BIT_RATE, /* bit rate */ A2D_AAC_IE_VBR_NOT_SUPP }; #endif /***************************************************************************** ** Local data *****************************************************************************/ typedef struct { UINT8 sep_info_idx; /* local SEP index (in BTA tables) */ UINT8 seid; /* peer SEP index (in peer tables) */ UINT8 codec_type; /* peer SEP codec type */ UINT8 codec_caps[AVDT_CODEC_SIZE]; /* peer SEP codec capabilities */ UINT8 num_protect; /* peer SEP number of CP elements */ UINT8 protect_info[BTA_AV_CP_INFO_LEN]; /* peer SEP content protection info */ } tBTA_AV_CO_SINK; typedef struct { BD_ADDR addr; /* address of audio/video peer */ /* array of supported sinks */ tBTA_AV_CO_SINK snks[BTIF_SV_AV_AA_SRC_SEP_INDEX - BTIF_SV_AV_AA_SBC_INDEX]; /* array of supported srcs */ tBTA_AV_CO_SINK srcs[BTIF_SV_AV_AA_SNK_SEP_INDEX - BTIF_SV_AV_AA_SBC_SINK_INDEX]; UINT8 num_snks; /* total number of sinks at peer */ UINT8 num_srcs; /* total number of srcs at peer */ UINT8 num_seps; /* total number of seids at peer */ UINT8 num_rx_snks; /* number of received sinks */ UINT8 num_rx_srcs; /* number of received srcs */ UINT8 num_sup_snks; /* number of supported sinks in the snks array */ UINT8 num_sup_srcs; /* number of supported srcs in the srcs array */ tBTA_AV_CO_SINK *p_snk; /* currently selected sink */ tBTA_AV_CO_SINK *p_src; /* currently selected src */ UINT8 codec_cfg[AVDT_CODEC_SIZE]; /* current codec configuration */ BOOLEAN cp_active; /* current CP configuration */ BOOLEAN acp; /* acceptor */ BOOLEAN recfg_needed; /* reconfiguration is needed */ BOOLEAN opened; /* opened */ UINT16 mtu; /* maximum transmit unit size */ UINT16 uuid_to_connect; /* uuid of peer device */ } tBTA_AV_CO_PEER; typedef struct { BOOLEAN active; UINT8 flag; } tBTA_AV_CO_CP; typedef struct { /* Connected peer information */ tBTA_AV_CO_PEER peers[BTA_AV_NUM_STRS]; /* Current codec configuration - access to this variable must be protected */ tBTIF_AV_CODEC_INFO* codec_cfg; tBTIF_AV_CODEC_INFO* codec_cfg_setconfig; /* remote peer setconfig preference */ UINT8 current_codec_id; tBTIF_AV_CODEC_INFO codec_cfg_sbc; tBTIF_AV_CODEC_INFO codec_cfg_sbc_setconfig; /* remote peer setconfig preference (SBC) */ tBTIF_AV_CODEC_INFO codec_cfg_aptx; tBTIF_AV_CODEC_INFO codec_cfg_aptx_setconfig; /* remote peer setconfig preference (aptX)*/ tBTIF_AV_CODEC_INFO codec_cfg_aptx_hd; tBTIF_AV_CODEC_INFO codec_cfg_aptx_hd_setconfig; /* remote peer setconfig preference (aptX HD) */ #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) tBTIF_AV_CODEC_INFO codec_cfg_aac; tBTIF_AV_CODEC_INFO codec_cfg_aac_setconfig; /* remote peer setconfig preference (AAC)*/ #endif tBTA_AV_CO_CP cp; } tBTA_AV_CO_CB; /* Control block instance */ static tBTA_AV_CO_CB bta_av_co_cb; static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg); static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer); static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo); static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink); static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index); static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg); static BOOLEAN bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg); static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index); #ifdef BTA_AV_SPLIT_A2DP_ENABLED extern BOOLEAN btif_av_is_codec_offload_supported(int codec); #else #define btif_av_is_codec_offload_supported(codec) (0) #endif extern BOOLEAN btif_av_is_offload_supported(); extern BOOLEAN bt_split_a2dp_enabled; /******************************************************************************* ** ** Function bta_av_co_cp_is_active ** ** Description Get the current configuration of content protection ** ** Returns TRUE if the current streaming has CP, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_cp_is_active(void) { FUNC_TRACE(); return bta_av_co_cb.cp.active; } /******************************************************************************* ** ** Function bta_av_co_cp_get_flag ** ** Description Get content protection flag ** BTA_AV_CP_SCMS_COPY_NEVER ** BTA_AV_CP_SCMS_COPY_ONCE ** BTA_AV_CP_SCMS_COPY_FREE ** ** Returns The current flag value ** *******************************************************************************/ UINT8 bta_av_co_cp_get_flag(void) { FUNC_TRACE(); return bta_av_co_cb.cp.flag; } /******************************************************************************* ** ** Function bta_av_co_cp_set_flag ** ** Description Set content protection flag ** BTA_AV_CP_SCMS_COPY_NEVER ** BTA_AV_CP_SCMS_COPY_ONCE ** BTA_AV_CP_SCMS_COPY_FREE ** ** Returns TRUE if setting the SCMS flag is supported else FALSE ** *******************************************************************************/ BOOLEAN bta_av_co_cp_set_flag(UINT8 cp_flag) { FUNC_TRACE(); #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) #else if (cp_flag != BTA_AV_CP_SCMS_COPY_FREE) { return FALSE; } #endif bta_av_co_cb.cp.flag = cp_flag; return TRUE; } /******************************************************************************* ** ** Function bta_av_co_get_peer ** ** Description find the peer entry for a given handle ** ** Returns the control block ** *******************************************************************************/ static tBTA_AV_CO_PEER *bta_av_co_get_peer(tBTA_AV_HNDL hndl) { UINT8 index; FUNC_TRACE(); index = BTA_AV_CO_AUDIO_HNDL_TO_INDX(hndl); /* Sanity check */ if (index >= BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers)) { APPL_TRACE_ERROR("bta_av_co_get_peer peer index out of bounds:%d", index); return NULL; } return &bta_av_co_cb.peers[index]; } /******************************************************************************* ** ** Function bta_av_co_audio_init ** ** Description This callout function is executed by AV when it is ** started by calling BTA_AvRegister(). This function can be ** used by the phone to initialize audio paths or for other ** initialization purposes. ** ** ** Returns Stream codec and content protection capabilities info. ** *******************************************************************************/ BOOLEAN bta_av_co_audio_init(UINT8 *p_codec_type, UINT8 *p_codec_info, UINT8 *p_num_protect, UINT8 *p_protect_info, UINT8 index) { FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_init: %d", index); /* By default - no content protection info */ *p_num_protect = 0; *p_protect_info = 0; /* reset remote preference through setconfig */ bta_av_co_cb.codec_cfg_setconfig = NULL; switch (index) { case BTIF_SV_AV_AA_SBC_INDEX: #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) { UINT8 *p = p_protect_info; /* Content protection info - support SCMS-T */ *p_num_protect = 1; *p++ = BTA_AV_CP_LOSC; UINT16_TO_STREAM(p, BTA_AV_CP_SCMS_T_ID); } #endif /* Set up for SBC codec for SRC*/ *p_codec_type = BTA_AV_CODEC_SBC; /* This should not fail because we are using constants for parameters */ A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_caps, p_codec_info); /* Codec is valid */ return TRUE; case BTIF_SV_AV_AA_APTX_INDEX: APPL_TRACE_DEBUG("%s aptX", __func__); /* Set up for aptX codec */ *p_codec_type = A2D_NON_A2DP_MEDIA_CT; A2D_BldAptxInfo(AVDT_MEDIA_AUDIO, (tA2D_APTX_CIE *) &bta_av_co_aptx_caps, p_codec_info); return TRUE; case BTIF_SV_AV_AA_APTX_HD_INDEX: APPL_TRACE_DEBUG("%s aptX HD", __func__); /* Set up for aptX HD codec */ *p_codec_type = A2D_NON_A2DP_MEDIA_CT; A2D_BldAptx_hdInfo(AVDT_MEDIA_AUDIO, (tA2D_APTX_HD_CIE *) &bta_av_co_aptx_hd_caps, p_codec_info); return TRUE; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) case BTIF_SV_AV_AA_AAC_INDEX: APPL_TRACE_DEBUG("%s AAC", __func__); *p_codec_type = BTA_AV_CODEC_M24; A2D_BldAacInfo(AVDT_MEDIA_AUDIO, (tA2D_AAC_CIE *) &bta_av_co_aac_caps ,p_codec_info); return TRUE; #endif #if (BTA_AV_SINK_INCLUDED == TRUE) case BTIF_SV_AV_AA_SBC_SINK_INDEX: *p_codec_type = BTA_AV_CODEC_SBC; /* This should not fail because we are using constants for parameters */ A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &bta_av_co_sbc_sink_caps, p_codec_info); /* Codec is valid */ return TRUE; #endif default: /* Not valid */ return FALSE; } } /******************************************************************************* ** ** Function bta_av_co_audio_disc_res ** ** Description This callout function is executed by AV to report the ** number of stream end points (SEP) were found during the ** AVDT stream discovery process. ** ** ** Returns void. ** *******************************************************************************/ void bta_av_co_audio_disc_res(tBTA_AV_HNDL hndl, UINT8 num_seps, UINT8 num_snk, UINT8 num_src, BD_ADDR addr, UINT16 uuid_local) { tBTA_AV_CO_PEER *p_peer; FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_disc_res h:x%x num_seps:%d num_snk:%d num_src:%d", hndl, num_seps, num_snk, num_src); /* Find the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR("bta_av_co_audio_disc_res could not find peer entry"); return; } /* Sanity check : this should never happen */ if (p_peer->opened) { APPL_TRACE_ERROR("bta_av_co_audio_disc_res peer already opened"); } /* Copy the discovery results */ bdcpy(p_peer->addr, addr); p_peer->num_snks = num_snk; p_peer->num_srcs = num_src; p_peer->num_seps = num_seps; p_peer->num_rx_snks = 0; p_peer->num_rx_srcs = 0; p_peer->num_sup_snks = 0; if (uuid_local == UUID_SERVCLASS_AUDIO_SINK) p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SOURCE; else if (uuid_local == UUID_SERVCLASS_AUDIO_SOURCE) p_peer->uuid_to_connect = UUID_SERVCLASS_AUDIO_SINK; } /******************************************************************************* ** ** Function bta_av_build_src_cfg ** ** Description This function will build preferred config from src capabilities ** ** ** Returns Pass or Fail for current getconfig. ** *******************************************************************************/ void bta_av_build_src_cfg (UINT8 *p_pref_cfg, UINT8 *p_src_cap) { tA2D_SBC_CIE src_cap; tA2D_SBC_CIE pref_cap; UINT8 status = 0; /* initialize it to default SBC configuration */ A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &btif_av_sbc_default_config, p_pref_cfg); /* now try to build a preferred one */ /* parse configuration */ if ((status = A2D_ParsSbcInfo(&src_cap, p_src_cap, TRUE)) != 0) { APPL_TRACE_DEBUG(" Cant parse src cap ret = %d", status); return ; } if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_48) pref_cap.samp_freq = A2D_SBC_IE_SAMP_FREQ_48; else if (src_cap.samp_freq & A2D_SBC_IE_SAMP_FREQ_44) pref_cap.samp_freq = A2D_SBC_IE_SAMP_FREQ_44; if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_JOINT) pref_cap.ch_mode = A2D_SBC_IE_CH_MD_JOINT; else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_STEREO) pref_cap.ch_mode = A2D_SBC_IE_CH_MD_STEREO; else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_DUAL) pref_cap.ch_mode = A2D_SBC_IE_CH_MD_DUAL; else if (src_cap.ch_mode & A2D_SBC_IE_CH_MD_MONO) pref_cap.ch_mode = A2D_SBC_IE_CH_MD_MONO; if (src_cap.block_len & A2D_SBC_IE_BLOCKS_16) pref_cap.block_len = A2D_SBC_IE_BLOCKS_16; else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_12) pref_cap.block_len = A2D_SBC_IE_BLOCKS_12; else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_8) pref_cap.block_len = A2D_SBC_IE_BLOCKS_8; else if (src_cap.block_len & A2D_SBC_IE_BLOCKS_4) pref_cap.block_len = A2D_SBC_IE_BLOCKS_4; if (src_cap.num_subbands & A2D_SBC_IE_SUBBAND_8) pref_cap.num_subbands = A2D_SBC_IE_SUBBAND_8; else if(src_cap.num_subbands & A2D_SBC_IE_SUBBAND_4) pref_cap.num_subbands = A2D_SBC_IE_SUBBAND_4; if (src_cap.alloc_mthd & A2D_SBC_IE_ALLOC_MD_L) pref_cap.alloc_mthd = A2D_SBC_IE_ALLOC_MD_L; else if(src_cap.alloc_mthd & A2D_SBC_IE_ALLOC_MD_S) pref_cap.alloc_mthd = A2D_SBC_IE_ALLOC_MD_S; pref_cap.max_bitpool = src_cap.max_bitpool; pref_cap.min_bitpool = src_cap.min_bitpool; A2D_BldSbcInfo(AVDT_MEDIA_AUDIO, (tA2D_SBC_CIE *) &pref_cap, p_pref_cfg); } /******************************************************************************* ** ** Function bta_av_audio_sink_getconfig ** ** Description This callout function is executed by AV to retrieve the ** desired codec and content protection configuration for the ** A2DP Sink audio stream in Initiator. ** ** ** Returns Pass or Fail for current getconfig. ** *******************************************************************************/ UINT8 bta_av_audio_sink_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect, UINT8 *p_protect_info) { UINT8 result = A2D_FAIL; BOOLEAN supported; tBTA_AV_CO_PEER *p_peer; tBTA_AV_CO_SINK *p_src; UINT8 pref_cfg[AVDT_CODEC_SIZE]; UINT8 index; FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig handle:0x%x codec_type:%d seid:%d", hndl, codec_type, seid); APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x", *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR("bta_av_audio_sink_getconfig could not find peer entry"); return A2D_FAIL; } APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", p_peer->opened, p_peer->num_srcs, p_peer->num_rx_srcs, p_peer->num_sup_srcs); p_peer->num_rx_srcs++; /* Check if this is a supported configuration */ supported = FALSE; switch (codec_type) { case BTA_AV_CODEC_SBC: supported = TRUE; break; default: break; } if (supported) { /* If there is room for a new one */ if (p_peer->num_sup_srcs < BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs)) { p_src = &p_peer->srcs[p_peer->num_sup_srcs++]; APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig saved caps[%x:%x:%x:%x:%x:%x]", p_codec_info[1], p_codec_info[2], p_codec_info[3], p_codec_info[4], p_codec_info[5], p_codec_info[6]); memcpy(p_src->codec_caps, p_codec_info, AVDT_CODEC_SIZE); p_src->codec_type = codec_type; p_src->sep_info_idx = *p_sep_info_idx; p_src->seid = seid; p_src->num_protect = *p_num_protect; memcpy(p_src->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN); } else { APPL_TRACE_ERROR("bta_av_audio_sink_getconfig no more room for SRC info"); } } /* If last SNK get capabilities or all supported codec caps retrieved */ if ((p_peer->num_rx_srcs == p_peer->num_srcs) || (p_peer->num_sup_srcs == BTA_AV_CO_NUM_ELEMENTS(p_peer->srcs))) { APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig last SRC reached"); /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_lock(); /* Find a src that matches the codec config */ if (bta_av_co_audio_peer_src_supports_codec(p_peer, &index)) { APPL_TRACE_DEBUG(" Codec Supported "); p_src = &p_peer->srcs[index]; /* Build the codec configuration for this sink */ { /* Save the new configuration */ p_peer->p_src = p_src; /* get preferred config from src_caps */ bta_av_build_src_cfg(pref_cfg, p_src->codec_caps); memcpy(p_peer->codec_cfg, pref_cfg, AVDT_CODEC_SIZE); APPL_TRACE_DEBUG("bta_av_audio_sink_getconfig p_codec_info[%x:%x:%x:%x:%x:%x]", p_peer->codec_cfg[1], p_peer->codec_cfg[2], p_peer->codec_cfg[3], p_peer->codec_cfg[4], p_peer->codec_cfg[5], p_peer->codec_cfg[6]); /* By default, no content protection */ *p_num_protect = 0; #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) p_peer->cp_active = FALSE; bta_av_co_cb.cp.active = FALSE; #endif *p_sep_info_idx = p_src->sep_info_idx; memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE); result = A2D_SUCCESS; } } /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_unlock(); } return result; } /******************************************************************************* ** ** Function bta_av_co_audio_getconfig ** ** Description This callout function is executed by AV to retrieve the ** desired codec and content protection configuration for the ** audio stream. ** ** ** Returns Stream codec and content protection configuration info. ** *******************************************************************************/ UINT8 bta_av_co_audio_getconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT8 *p_sep_info_idx, UINT8 seid, UINT8 *p_num_protect, UINT8 *p_protect_info) { UINT8 result = A2D_FAIL; BOOLEAN supported; tBTA_AV_CO_PEER *p_peer; tBTA_AV_CO_SINK *p_sink; UINT8 codec_cfg[AVDT_CODEC_SIZE]; UINT8 index; FUNC_TRACE(); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR("bta_av_co_audio_getconfig could not find peer entry"); return A2D_FAIL; } if (p_peer->uuid_to_connect == UUID_SERVCLASS_AUDIO_SOURCE) { result = bta_av_audio_sink_getconfig(hndl, codec_type, p_codec_info, p_sep_info_idx, seid, p_num_protect, p_protect_info); return result; } APPL_TRACE_DEBUG("bta_av_co_audio_getconfig handle:0x%x codec_type:%d seid:%d", hndl, codec_type, seid); APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x", *p_num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); APPL_TRACE_DEBUG("bta_av_co_audio_getconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks); p_peer->num_rx_snks++; /* Check if this is a supported configuration */ supported = FALSE; switch (codec_type) { case BTA_AV_CODEC_SBC: supported = TRUE; break; case A2D_NON_A2DP_MEDIA_CT: { UINT16 codecId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->codecId; UINT32 vendorId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->vendorId; APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId ); APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId ); if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) { /* aptX */ supported = TRUE; } else if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID) { /* aptX HD */ supported = TRUE; } break; } #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) case BTA_AV_CODEC_M24: APPL_TRACE_DEBUG("%s: AAC is supported", __func__); supported = TRUE; break; #endif default: break; } if (supported) { /* If there is room for a new one */ if (p_peer->num_sup_snks < BTA_AV_CO_NUM_ELEMENTS(p_peer->snks)) { int i = 0; p_sink = &p_peer->snks[p_peer->num_sup_snks++]; APPL_TRACE_DEBUG("bta_av_co_audio_getconfig saved caps[%x:%x:%x:%x:%x:%x]", p_codec_info[1], p_codec_info[2], p_codec_info[3], p_codec_info[4], p_codec_info[5], p_codec_info[6]); for (i = 0 ; i < AVDT_CODEC_SIZE; i++) APPL_TRACE_DEBUG("%s p_codec_info[%d]: %x", __func__, i, p_codec_info[i]); if (codec_type == A2D_NON_A2DP_MEDIA_CT) memcpy(p_sink->codec_caps, &p_codec_info[BTA_AV_CFG_START_IDX], AVDT_CODEC_SIZE); else memcpy(p_sink->codec_caps, p_codec_info, AVDT_CODEC_SIZE); p_sink->codec_type = codec_type; p_sink->sep_info_idx = *p_sep_info_idx; p_sink->seid = seid; p_sink->num_protect = *p_num_protect; memcpy(p_sink->protect_info, p_protect_info, BTA_AV_CP_INFO_LEN); } else { APPL_TRACE_ERROR("bta_av_co_audio_getconfig no more room for SNK info"); } } /* If last SNK get capabilities or all supported codec capa retrieved */ if ((p_peer->num_rx_snks == p_peer->num_snks) || (p_peer->num_sup_snks == BTA_AV_CO_NUM_ELEMENTS(p_peer->snks))) { APPL_TRACE_DEBUG("bta_av_co_audio_getconfig last sink reached"); /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_lock(); /* Find a sink that matches the codec config */ if (bta_av_co_audio_peer_supports_codec(p_peer, &index)) { /* stop fetching caps once we retrieved a supported codec */ if (p_peer->acp) { *p_sep_info_idx = p_peer->num_seps; APPL_TRACE_EVENT("no need to fetch more SEPs"); } p_sink = &p_peer->snks[index]; /* Build the codec configuration for this sink */ if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) { int i = 0; APPL_TRACE_DEBUG("bta_av_co_audio_getconfig reconfig p_codec_info[%x:%x:%x:%x:%x:%x]", codec_cfg[1], codec_cfg[2], codec_cfg[3], codec_cfg[4], codec_cfg[5], codec_cfg[6]); for (i = 0 ; i < AVDT_CODEC_SIZE; i++) APPL_TRACE_DEBUG("%s p_codec_info[%d]: %x", __func__, i, p_codec_info[i]); /* Save the new configuration */ p_peer->p_snk = p_sink; memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE); /* By default, no content protection */ *p_num_protect = 0; #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) /* Check if this sink supports SCMS */ if (bta_av_co_audio_sink_has_scmst(p_sink)) { p_peer->cp_active = TRUE; bta_av_co_cb.cp.active = TRUE; *p_num_protect = BTA_AV_CP_INFO_LEN; memcpy(p_protect_info, bta_av_co_cp_scmst, BTA_AV_CP_INFO_LEN); } else { p_peer->cp_active = FALSE; bta_av_co_cb.cp.active = FALSE; } #endif /* If acceptor -> reconfig otherwise reply for configuration */ if (p_peer->acp) { if (p_peer->recfg_needed) { APPL_TRACE_DEBUG("bta_av_co_audio_getconfig call BTA_AvReconfig(x%x)", hndl); BTA_AvReconfig(hndl, TRUE, p_sink->sep_info_idx, p_peer->codec_cfg, *p_num_protect, (UINT8 *)bta_av_co_cp_scmst); } } else { *p_sep_info_idx = p_sink->sep_info_idx; memcpy(p_codec_info, p_peer->codec_cfg, AVDT_CODEC_SIZE); } result = A2D_SUCCESS; } } /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_unlock(); } return result; } /******************************************************************************* ** ** Function bta_av_co_audio_setconfig ** ** Description This callout function is executed by AV to set the codec and ** content protection configuration of the audio stream. ** ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_setconfig(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT8 seid, BD_ADDR addr, UINT8 num_protect, UINT8 *p_protect_info, UINT8 t_local_sep, UINT8 avdt_handle) { tBTA_AV_CO_PEER *p_peer; UINT8 status = A2D_SUCCESS; UINT8 category = A2D_SUCCESS; BOOLEAN recfg_needed = FALSE; BOOLEAN codec_cfg_supported = FALSE; UNUSED(seid); UNUSED(addr); FUNC_TRACE(); APPL_TRACE_IMP("bta_av_co_audio_setconfig p_codec_info[%x:%x:%x:%x:%x:%x]", p_codec_info[1], p_codec_info[2], p_codec_info[3], p_codec_info[4], p_codec_info[5], p_codec_info[6]); APPL_TRACE_DEBUG("num_protect:0x%02x protect_info:0x%02x%02x%02x", num_protect, p_protect_info[0], p_protect_info[1], p_protect_info[2]); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR("bta_av_co_audio_setconfig could not find peer entry"); /* Call call-in rejecting the configuration */ bta_av_ci_setconfig(hndl, A2D_BUSY, AVDT_ASC_CODEC, 0, NULL, FALSE, avdt_handle); return; } APPL_TRACE_DEBUG("bta_av_co_audio_setconfig peer(o=%d,n_snks=%d,n_rx_snks=%d,n_sup_snks=%d)", p_peer->opened, p_peer->num_snks, p_peer->num_rx_snks, p_peer->num_sup_snks); /* Sanity check: should not be opened at this point */ if (p_peer->opened) { APPL_TRACE_ERROR("bta_av_co_audio_setconfig peer already in use"); } #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) if (num_protect != 0) { /* If CP is supported */ if ((num_protect != 1) || (bta_av_co_cp_is_scmst(p_protect_info) == FALSE)) { APPL_TRACE_ERROR("bta_av_co_audio_setconfig wrong CP configuration"); status = A2D_BAD_CP_TYPE; category = AVDT_ASC_PROTECT; } } #else /* Do not support content protection for the time being */ if (num_protect != 0) { APPL_TRACE_ERROR("bta_av_co_audio_setconfig wrong CP configuration"); status = A2D_BAD_CP_TYPE; category = AVDT_ASC_PROTECT; } #endif if (status == A2D_SUCCESS) { if(AVDT_TSEP_SNK == t_local_sep) { codec_cfg_supported = bta_av_co_audio_sink_supports_config(codec_type, p_codec_info); APPL_TRACE_DEBUG(" Peer is A2DP SRC "); } if(AVDT_TSEP_SRC == t_local_sep) { codec_cfg_supported = bta_av_co_audio_media_supports_config(codec_type, p_codec_info); APPL_TRACE_DEBUG(" Peer is A2DP SINK "); } /* Check if codec configuration is supported */ if (codec_cfg_supported) { /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_lock(); /* Check if the configuration matches the current codec config */ switch (codec_type) { case BTIF_AV_CODEC_SBC: if ((codec_type != BTA_AV_CODEC_SBC) || memcmp(p_codec_info, bta_av_co_cb.codec_cfg->info, 5)) { recfg_needed = TRUE; } else if ((num_protect == 1) && (!bta_av_co_cb.cp.active)) { recfg_needed = TRUE; } /* if remote side requests a restricted notify sinks preferred bitpool range as all other params are already checked for validify */ APPL_TRACE_DEBUG("%s SBC", __func__); APPL_TRACE_EVENT("remote peer setconfig bitpool range [%d:%d]", p_codec_info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] ); bta_av_co_cb.codec_cfg_sbc_setconfig.id = BTIF_AV_CODEC_SBC; memcpy(bta_av_co_cb.codec_cfg_sbc_setconfig.info, p_codec_info, AVDT_CODEC_SIZE); bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_sbc_setconfig; memcpy(bta_av_co_cb.codec_cfg_sbc.info, p_codec_info, AVDT_CODEC_SIZE); memcpy(bta_av_co_cb.codec_cfg->info, p_codec_info, AVDT_CODEC_SIZE); if(AVDT_TSEP_SNK == t_local_sep) { /* If Peer is SRC, and our cfg subset matches with what is requested by peer, then just accept what peer wants */ recfg_needed = FALSE; } break; case A2D_NON_A2DP_MEDIA_CT: { UINT16 codecId; UINT32 vendorId; codecId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->codecId; vendorId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->vendorId; APPL_TRACE_DEBUG("%s codec_type = %x", __func__, codec_type); APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId); APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId); if ((codec_type != A2D_NON_A2DP_MEDIA_CT) || (codecId != A2D_APTX_CODEC_ID_BLUETOOTH) || (vendorId != A2D_APTX_VENDOR_ID) || memcmp(p_codec_info, bta_av_co_cb.codec_cfg_aptx.info, 5)) { APPL_TRACE_DEBUG("%s recfg_needed", __func__); recfg_needed = TRUE; } else if ((num_protect == 1) && (!bta_av_co_cb.cp.active)) { APPL_TRACE_DEBUG("%s recfg_needed", __func__); recfg_needed = TRUE; } if ((codecId == A2D_APTX_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_VENDOR_ID)) { APPL_TRACE_DEBUG("%s aptX", __func__); bta_av_co_cb.codec_cfg_aptx_setconfig.id = A2D_NON_A2DP_MEDIA_CT; memcpy(bta_av_co_cb.codec_cfg_aptx_setconfig.info, p_codec_info, AVDT_CODEC_SIZE); bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_aptx_setconfig; } else if ((codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_HD_VENDOR_ID)) { APPL_TRACE_DEBUG("%s aptX HD", __func__); bta_av_co_cb.codec_cfg_aptx_hd_setconfig.id = A2D_NON_A2DP_MEDIA_CT; memcpy(bta_av_co_cb.codec_cfg_aptx_hd_setconfig.info, p_codec_info, AVDT_CODEC_SIZE); bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_aptx_hd_setconfig; } break; } #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) case BTA_AV_CODEC_M24: { APPL_TRACE_DEBUG("%s AAC", __func__); bta_av_co_cb.codec_cfg_aac_setconfig.id = BTIF_AV_CODEC_M24; memcpy(bta_av_co_cb.codec_cfg_aac_setconfig.info, p_codec_info, AVDT_CODEC_SIZE); bta_av_co_cb.codec_cfg_setconfig = &bta_av_co_cb.codec_cfg_aac_setconfig; APPL_TRACE_DEBUG("%s codec_type = %x", __func__, codec_type); } break; #endif default: APPL_TRACE_ERROR("bta_av_co_audio_setconfig unsupported cid %d", bta_av_co_cb.codec_cfg->id); recfg_needed = TRUE; break; } /* Protect access to bta_av_co_cb.codec_cfg */ mutex_global_unlock(); } else { category = AVDT_ASC_CODEC; status = A2D_WRONG_CODEC; } } if (status != A2D_SUCCESS) { APPL_TRACE_ERROR("bta_av_co_audio_setconfig reject s=%d c=%d", status, category); /* Call call-in rejecting the configuration */ bta_av_ci_setconfig(hndl, status, category, 0, NULL, FALSE, avdt_handle); } else { /* Mark that this is an acceptor peer */ p_peer->acp = TRUE; p_peer->recfg_needed = recfg_needed; APPL_TRACE_DEBUG("bta_av_co_audio_setconfig accept reconf=%d", recfg_needed); /* Call call-in accepting the configuration */ bta_av_ci_setconfig(hndl, A2D_SUCCESS, A2D_SUCCESS, 0, NULL, recfg_needed, avdt_handle); } } /******************************************************************************* ** ** Function bta_av_co_audio_open ** ** Description This function is called by AV when the audio stream connection ** is opened. ** ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_open(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, UINT16 mtu) { tBTA_AV_CO_PEER *p_peer; UNUSED(p_codec_info); FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_open mtu:%d codec_type:%d", mtu, codec_type); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR("bta_av_co_audio_setconfig could not find peer entry"); } else { p_peer->opened = TRUE; p_peer->mtu = mtu; } } /******************************************************************************* ** ** Function bta_av_co_audio_close ** ** Description This function is called by AV when the audio stream connection ** is closed. ** ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_close(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT16 mtu) { tBTA_AV_CO_PEER *p_peer; UNUSED(codec_type); UNUSED(mtu); FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_close"); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer) { /* Mark the peer closed and clean the peer info */ memset(p_peer, 0, sizeof(*p_peer)); } else { APPL_TRACE_ERROR("bta_av_co_audio_close could not find peer entry"); } /* reset remote preference through setconfig */ bta_av_co_cb.codec_cfg_setconfig = NULL; } /******************************************************************************* ** ** Function bta_av_co_audio_start ** ** Description This function is called by AV when the audio streaming data ** transfer is started. ** ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_start(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type, UINT8 *p_codec_info, BOOLEAN *p_no_rtp_hdr) { UNUSED(hndl); FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_start"); if (codec_type == A2D_NON_A2DP_MEDIA_CT) { UINT16 codecId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->codecId; UINT32 vendorId = ((tA2D_APTX_CIE*)(&p_codec_info[BTA_AV_CFG_START_IDX]))->vendorId; // for aptX, we only add RTP hdr along with CP if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) { if (!bta_av_co_cb.cp.active) *p_no_rtp_hdr = TRUE; } } } /******************************************************************************* ** ** Function bta_av_co_audio_stop ** ** Description This function is called by AV when the audio streaming data ** transfer is stopped. ** ** ** Returns void ** *******************************************************************************/ extern void bta_av_co_audio_stop(tBTA_AV_HNDL hndl, tBTA_AV_CODEC codec_type) { UNUSED(hndl); UNUSED(codec_type); FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_stop"); } /******************************************************************************* ** ** Function bta_av_co_audio_src_data_path ** ** Description This function is called to manage data transfer from ** the audio codec to AVDTP. ** ** Returns Pointer to the GKI buffer to send, NULL if no buffer to send ** *******************************************************************************/ void * bta_av_co_audio_src_data_path(tBTA_AV_CODEC codec_type, UINT32 *p_len, UINT32 *p_timestamp) { BT_HDR *p_buf; UNUSED(p_len); FUNC_TRACE(); p_buf = btif_media_aa_readbuf(); if (p_buf != NULL) { switch (codec_type) { case BTA_AV_CODEC_SBC: /* In media packet SBC, the following information is available: * p_buf->layer_specific : number of SBC frames in the packet * p_buf->word[0] : timestamp */ /* Retrieve the timestamp information from the media packet */ *p_timestamp = *((UINT32 *) (p_buf + 1)); /* Set up packet header */ bta_av_sbc_bld_hdr(p_buf, p_buf->layer_specific); break; case A2D_NON_A2DP_MEDIA_CT: /* Retrieve the timestamp information from the media packet */ *p_timestamp = *((UINT32 *) (p_buf + 1)); break; default: APPL_TRACE_ERROR("bta_av_co_audio_src_data_path Unsupported codec type (%d)", codec_type); break; } #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) { UINT8 *p; if (bta_av_co_cp_is_active()) { p_buf->len++; p_buf->offset--; p = (UINT8 *)(p_buf + 1) + p_buf->offset; *p = bta_av_co_cp_get_flag(); } } #endif } return p_buf; } /******************************************************************************* ** ** Function bta_av_co_audio_drop ** ** Description An Audio packet is dropped. . ** It's very likely that the connected headset with this handle ** is moved far away. The implementation may want to reduce ** the encoder bit rate setting to reduce the packet size. ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_drop(tBTA_AV_HNDL hndl) { FUNC_TRACE(); APPL_TRACE_ERROR("bta_av_co_audio_drop dropped: x%x", hndl); } /******************************************************************************* ** ** Function bta_av_co_audio_delay ** ** Description This function is called by AV when the audio stream connection ** needs to send the initial delay report to the connected SRC. ** ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_delay(tBTA_AV_HNDL hndl, UINT16 delay) { FUNC_TRACE(); APPL_TRACE_ERROR("bta_av_co_audio_delay handle: x%x, delay:0x%x", hndl, delay); } /******************************************************************************* ** ** Function bta_av_co_audio_codec_build_config ** ** Description Build the codec configuration ** ** Returns TRUE if the codec was built successfully, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_codec_build_config(const UINT8 *p_codec_caps, UINT8 *p_codec_cfg) { FUNC_TRACE(); tA2D_AAC_CIE peer_aac_cfg; tA2D_AAC_CIE aac_cfg_selected; memset(p_codec_cfg, 0, AVDT_CODEC_SIZE); switch (bta_av_co_cb.codec_cfg->id) { case BTIF_AV_CODEC_SBC: /* only copy the relevant portions for this codec to avoid issues when comparing codec configs covering larger codec sets than SBC (7 bytes) */ memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, BTA_AV_CO_SBC_MAX_BITPOOL_OFF+1); /* Update the bit pool boundaries with the codec capabilities */ p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]; p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF] = p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]; APPL_TRACE_DEBUG("%s SBC", __func__); APPL_TRACE_EVENT("bta_av_co_audio_codec_build_config : bitpool min %d, max %d", p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); break; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) case BTIF_AV_CODEC_M24: /* only copy the relevant portions for this codec to avoid issues when comparing codec configs covering larger codec sets than SBC (7 bytes) */ A2D_ParsAacInfo (&peer_aac_cfg ,(UINT8*)p_codec_caps, FALSE); A2D_ParsAacInfo (&aac_cfg_selected ,bta_av_co_cb.codec_cfg->info, FALSE); aac_cfg_selected.bit_rate = BTA_AV_CO_MIN(peer_aac_cfg.bit_rate, aac_cfg_selected.bit_rate); APPL_TRACE_EVENT("%s AAC bitrate selected %d", __func__, aac_cfg_selected.bit_rate); //update with new value A2D_BldAacInfo (AVDT_MEDIA_AUDIO, &aac_cfg_selected, bta_av_co_cb.codec_cfg->info); memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, A2D_AAC_INFO_LEN+1); APPL_TRACE_DEBUG("%s AAC", __func__); break; #endif case A2D_NON_A2DP_MEDIA_CT: { UINT16 codecId; UINT16 vendorId; codecId = ((tA2D_APTX_CIE*)p_codec_caps)->codecId; vendorId = ((tA2D_APTX_CIE*)p_codec_caps)->vendorId; APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId); APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId); if ((codecId == A2D_APTX_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_VENDOR_ID)) { memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, A2D_APTX_CODEC_LEN+1); APPL_TRACE_DEBUG("%s aptX",__func__); } else if ((codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH) && (vendorId == A2D_APTX_HD_VENDOR_ID)) { memcpy(p_codec_cfg, bta_av_co_cb.codec_cfg->info, A2D_APTX_HD_CODEC_LEN+1); APPL_TRACE_DEBUG("%s aptX HD",__func__); } break; } default: APPL_TRACE_ERROR("bta_av_co_audio_codec_build_config: unsupported codec id %d", bta_av_co_cb.codec_cfg->id); return FALSE; break; } return TRUE; } /******************************************************************************* ** ** Function bta_av_co_audio_codec_cfg_matches_caps ** ** Description Check if a codec config matches a codec capabilities ** ** Returns TRUE if it codec config is supported, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_codec_cfg_matches_caps(UINT8 codec_id, const UINT8 *p_codec_caps, const UINT8 *p_codec_cfg) { FUNC_TRACE(); switch(codec_id) { case BTIF_AV_CODEC_SBC: APPL_TRACE_EVENT("bta_av_co_audio_codec_cfg_matches_caps : min %d/%d max %d/%d", p_codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_cfg[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], p_codec_cfg[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]); /* Must match all items exactly except bitpool boundaries which can be adjusted */ if (!((p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF] & p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF]) && (p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF] & p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]))) { APPL_TRACE_EVENT("FALSE %x %x %x %x", p_codec_caps[BTA_AV_CO_SBC_FREQ_CHAN_OFF], p_codec_cfg[BTA_AV_CO_SBC_FREQ_CHAN_OFF], p_codec_caps[BTA_AV_CO_SBC_BLOCK_BAND_OFF], p_codec_cfg[BTA_AV_CO_SBC_BLOCK_BAND_OFF]); return FALSE; } break; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) /* in case of Sink we have to match if Src Cap is a subset of ours */ case BTA_AV_CODEC_M24: { tBTIF_AV_CODEC_INFO *p_local_aac_cfg = (tBTIF_AV_CODEC_INFO*)p_codec_cfg; tA2D_AAC_CIE p_local_aac_caps; tA2D_AAC_CIE p_snk_aac_caps; if (A2D_ParsAacInfo(&p_local_aac_caps, (UINT8*)p_local_aac_cfg, FALSE) != A2D_SUCCESS) { APPL_TRACE_ERROR("%s: A2D_BldAacInfo: LOCAL failed", __func__); } if (A2D_ParsAacInfo(&p_snk_aac_caps, (UINT8*)p_codec_cfg, FALSE) != A2D_SUCCESS) { APPL_TRACE_ERROR("%s: A2D_BldAacInfo: SNK failed", __func__); } APPL_TRACE_EVENT("AAC obj_type: snk %x local %x", p_snk_aac_caps.object_type, p_local_aac_caps.object_type); APPL_TRACE_EVENT("AAC samp_freq: snk %x local %x", p_snk_aac_caps.samp_freq, p_local_aac_caps.samp_freq); APPL_TRACE_EVENT("AAC channels: snk %x local %x", p_snk_aac_caps.channels, p_local_aac_caps.channels); APPL_TRACE_EVENT("AAC bit_rate: snk %x local %x", p_snk_aac_caps.bit_rate, p_local_aac_caps.bit_rate); APPL_TRACE_EVENT("AAC vbr: snk %x local %x", p_snk_aac_caps.vbr, p_local_aac_caps.vbr); return (((p_snk_aac_caps.object_type)&(p_local_aac_caps.object_type))&& ((p_snk_aac_caps.samp_freq)&(p_local_aac_caps.samp_freq))&& ((p_snk_aac_caps.channels)&(p_local_aac_caps.channels))); } break; #endif case A2D_NON_A2DP_MEDIA_CT: { UINT16 codecId; UINT32 vendorId; UINT8* aptx_capabilities; APPL_TRACE_DEBUG("%s aptX", __func__); aptx_capabilities = &(((tBTA_AV_CO_SINK*)p_codec_cfg)->codec_caps[0]); codecId = ((tA2D_APTX_CIE*)p_codec_caps)->codecId; vendorId = ((tA2D_APTX_CIE*)p_codec_caps)->vendorId; APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId); APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId); int i = 0; for (i = 0 ; i < AVDT_CODEC_SIZE; i++) APPL_TRACE_DEBUG("%s p_codec_cfg[%d]: %x", __func__, i, p_codec_cfg[i]); APPL_TRACE_EVENT("%s Caps -> sample rate/channel mode: %x configured %x", __func__, p_codec_caps[6], p_codec_cfg[9]); if (((vendorId != ((tA2D_APTX_CIE*)(aptx_capabilities))->vendorId) || /*vendor id*/ (codecId != ((tA2D_APTX_CIE*)(aptx_capabilities))->codecId) || /*codec id*/ ((p_codec_caps[6] & p_codec_cfg[9]) == 0 ) /*sampling rate & channel mode*/ )) { APPL_TRACE_DEBUG("%s aptX config don't match", __func__); APPL_TRACE_EVENT("%s Caps -> vendor id: %x %x %x %x", __func__, p_codec_caps[0], p_codec_caps[1], p_codec_caps[2], p_codec_caps[3]); APPL_TRACE_EVENT("%s Configured: %x %x %x %x", __func__, p_codec_cfg[3], p_codec_cfg[4], p_codec_cfg[5], p_codec_cfg[6]); APPL_TRACE_EVENT("%s Caps -> codec id: %x", __func__, p_codec_caps[4]); APPL_TRACE_EVENT("%s Configured: %x ", __func__, p_codec_cfg[7]); APPL_TRACE_EVENT("%s Caps -> Sample Rate/Channel Mode: %x Configured: %x", __func__, p_codec_caps[6], p_codec_cfg[9]); return FALSE; } break; } default: APPL_TRACE_ERROR("bta_av_co_audio_codec_cfg_matches_caps: unsupported codec id %d", codec_id); return FALSE; break; } APPL_TRACE_EVENT("TRUE"); return TRUE; } /******************************************************************************* ** ** Function bta_av_co_audio_codec_match ** ** Description Check if a codec capabilities supports the codec config ** ** Returns TRUE if the connection supports this codec, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_codec_match(const UINT8 *p_codec_caps, UINT8 codec_id) { FUNC_TRACE(); switch(codec_id) { case BTIF_AV_CODEC_SBC: return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_sbc.id, p_codec_caps, bta_av_co_cb.codec_cfg_sbc.info); break; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) case BTIF_AV_CODEC_M24: return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_aac.id, p_codec_caps, bta_av_co_cb.codec_cfg_aac.info); break; #endif case A2D_NON_A2DP_MEDIA_CT: { UINT16 codecId; UINT32 vendorId; int i = 0; for (i = 0 ; i < AVDT_CODEC_SIZE; i++) APPL_TRACE_DEBUG("%s p_codec_caps[%d]: %x", __func__, i, p_codec_caps[i]); codecId = ((tA2D_APTX_CIE*)p_codec_caps)->codecId; vendorId = ((tA2D_APTX_CIE*)p_codec_caps)->vendorId; APPL_TRACE_DEBUG("%s codecId = %d ", __func__, codecId); APPL_TRACE_DEBUG("%s vendorId = %x ", __func__, vendorId); if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) { /* aptX Classic */ APPL_TRACE_DEBUG("%s aptX", __func__); return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_aptx.id, p_codec_caps, bta_av_co_cb.codec_cfg_aptx.info); break; } else if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID) { /* aptX HD */ APPL_TRACE_DEBUG("%s aptX HD", __func__); return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_aptx_hd.id, p_codec_caps, bta_av_co_cb.codec_cfg_aptx_hd.info); break; } else { APPL_TRACE_ERROR("%s incorrect codecId (%d)", __func__, codecId); APPL_TRACE_ERROR("%s incorrect vendorId (%x)", __func__, vendorId); break; } } default: return bta_av_co_audio_codec_cfg_matches_caps(bta_av_co_cb.codec_cfg_sbc.id, p_codec_caps, bta_av_co_cb.codec_cfg_sbc.info); break; } return TRUE; } /******************************************************************************* ** ** Function bta_av_co_audio_peer_reset_config ** ** Description Reset the peer codec configuration ** ** Returns Nothing ** *******************************************************************************/ static void bta_av_co_audio_peer_reset_config(tBTA_AV_CO_PEER *p_peer) { FUNC_TRACE(); /* Indicate that there is no currently selected sink */ p_peer->p_snk = NULL; } /******************************************************************************* ** ** Function bta_av_co_cp_is_scmst ** ** Description Check if a content protection service is SCMS-T ** ** Returns TRUE if this CP is SCMS-T, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_cp_is_scmst(const UINT8 *p_protectinfo) { UINT16 cp_id; FUNC_TRACE(); if (*p_protectinfo >= BTA_AV_CP_LOSC) { p_protectinfo++; STREAM_TO_UINT16(cp_id, p_protectinfo); if (cp_id == BTA_AV_CP_SCMS_T_ID) { APPL_TRACE_DEBUG("bta_av_co_cp_is_scmst: SCMS-T found"); return TRUE; } } return FALSE; } /******************************************************************************* ** ** Function bta_av_co_audio_sink_has_scmst ** ** Description Check if a sink supports SCMS-T ** ** Returns TRUE if the sink supports this CP, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_sink_has_scmst(const tBTA_AV_CO_SINK *p_sink) { UINT8 index; const UINT8 *p; FUNC_TRACE(); /* Check if sink supports SCMS-T */ index = p_sink->num_protect; p = &p_sink->protect_info[0]; while (index) { if (bta_av_co_cp_is_scmst(p)) { return TRUE; } /* Move to the next SC */ p += *p + 1; /* Decrement the SC counter */ index--; } APPL_TRACE_DEBUG("bta_av_co_audio_sink_has_scmst: SCMS-T not found"); return FALSE; } /******************************************************************************* ** ** Function bta_av_co_audio_sink_supports_cp ** ** Description Check if a sink supports the current content protection ** ** Returns TRUE if the sink supports this CP, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_sink_supports_cp(const tBTA_AV_CO_SINK *p_sink) { FUNC_TRACE(); /* Check if content protection is enabled for this stream */ if (bta_av_co_cp_get_flag() != BTA_AV_CP_SCMS_COPY_FREE) { return bta_av_co_audio_sink_has_scmst(p_sink); } else { APPL_TRACE_DEBUG("bta_av_co_audio_sink_supports_cp: not required"); return TRUE; } } /******************************************************************************* ** ** Function bta_av_co_audio_peer_supports_codec ** ** Description Check if a connection supports the codec config ** ** Returns TRUE if the connection supports this codec, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_peer_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_snk_index) { int index; UINT8 codec_type; FUNC_TRACE(); /* Configure the codec type to look for */ codec_type = bta_av_co_cb.codec_cfg->id; /* Check for aptX HD before aptX Classic as * this is order of priority, if supported return true. * multicast is not supported for aptX */ if ((!bt_split_a2dp_enabled && isA2dAptXEnabled && (btif_av_is_multicast_supported() == FALSE)) || (bt_split_a2dp_enabled && (btif_av_is_codec_offload_supported(APTX)|| btif_av_is_codec_offload_supported(APTXHD)))) { UINT16 codecId; UINT32 vendorId; UINT8* aptx_capabilities; if ((bt_split_a2dp_enabled && btif_av_is_codec_offload_supported(APTXHD)) || isA2dAptXHdEnabled) { for (index = 0; index < p_peer->num_sup_snks; index++) { if (p_peer->snks[index].codec_type == A2D_NON_A2DP_MEDIA_CT) { aptx_capabilities = &(p_peer->snks[index].codec_caps[0]); codecId = ((tA2D_APTX_HD_CIE*)aptx_capabilities)->codecId; vendorId = ((tA2D_APTX_HD_CIE*)aptx_capabilities)->vendorId; int i = 0; for ( i = 0 ; i < AVDT_CODEC_SIZE; i++) { APPL_TRACE_DEBUG("%s codec_caps[%d]: %x", __func__, i, p_peer->snks[index].codec_caps[i]); } APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId); APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId); APPL_TRACE_DEBUG("%s p_peer->snks[index].codec_type = %x", __func__, p_peer->snks[index].codec_type ); if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID ) { if (p_snk_index) *p_snk_index = index; APPL_TRACE_DEBUG("%s aptX HD", __func__); if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, A2D_NON_A2DP_MEDIA_CT)) { #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index])) #endif { bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_aptx_hd.id; bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_aptx_hd; return TRUE; } } } } } } for (index = 0; index < p_peer->num_sup_snks; index++) { if (p_peer->snks[index].codec_type == A2D_NON_A2DP_MEDIA_CT) { aptx_capabilities = &(p_peer->snks[index].codec_caps[0]); codecId = ((tA2D_APTX_CIE*)aptx_capabilities)->codecId; vendorId = ((tA2D_APTX_CIE*)aptx_capabilities)->vendorId; int i = 0; for ( i = 0 ; i < AVDT_CODEC_SIZE; i++) { APPL_TRACE_DEBUG("%s codec_caps[%d]: %x", __func__, i, p_peer->snks[index].codec_caps[i]); } APPL_TRACE_DEBUG("%s codecId = %d", __func__, codecId); APPL_TRACE_DEBUG("%s vendorId = %x", __func__, vendorId); APPL_TRACE_DEBUG("%s p_peer->snks[index].codec_type = %x", __func__, p_peer->snks[index].codec_type ); if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) { if (p_snk_index) *p_snk_index = index; APPL_TRACE_DEBUG("%s aptX", __func__); if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, A2D_NON_A2DP_MEDIA_CT)) { #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index])) #endif { bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_aptx.id; bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_aptx; return TRUE; } } } } } } else APPL_TRACE_DEBUG("%s aptX is disabled", __func__); #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) if (bt_split_a2dp_enabled && btif_av_is_codec_offload_supported(AAC)) { for (index = 0; index < p_peer->num_sup_snks; index++) { APPL_TRACE_DEBUG("%s AAC: index: %d, codec_type: %d", __func__, index, p_peer->snks[index].codec_type); if (p_peer->snks[index].codec_type == bta_av_co_cb.codec_cfg_aac.id) { switch (p_peer->snks[index].codec_type) { case BTIF_AV_CODEC_M24: if (p_snk_index) *p_snk_index = index; APPL_TRACE_DEBUG("%s AAC", __func__); if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, BTIF_AV_CODEC_M24)) { #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index])) #endif { bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_aac.id; bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_aac; APPL_TRACE_DEBUG("%s AAC matched", __func__); return TRUE; } } break; default: APPL_TRACE_ERROR("AAC: bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg->id); //Fall thru for further SBC check break; } } } } else APPL_TRACE_DEBUG("%s aptX is disabled", __func__); #endif for (index = 0; index < p_peer->num_sup_snks; index++) { if (p_peer->snks[index].codec_type == codec_type || p_peer->snks[index].codec_type == bta_av_co_cb.codec_cfg_sbc.id) { switch (p_peer->snks[index].codec_type) { case BTIF_AV_CODEC_SBC: if (p_snk_index) *p_snk_index = index; APPL_TRACE_DEBUG("%s SBC", __func__); if (bta_av_co_audio_codec_match(p_peer->snks[index].codec_caps, BTIF_AV_CODEC_SBC)) { #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) if (bta_av_co_audio_sink_has_scmst(&p_peer->snks[index])) #endif { bta_av_co_cb.current_codec_id = bta_av_co_cb.codec_cfg_sbc.id; bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_sbc; return TRUE; } } break; default: APPL_TRACE_ERROR("bta_av_co_audio_peer_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg->id); return FALSE; break; } } } return FALSE; } /******************************************************************************* ** ** Function bta_av_co_audio_peer_src_supports_codec ** ** Description Check if a peer acting as src supports codec config ** ** Returns TRUE if the connection supports this codec, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_peer_src_supports_codec(tBTA_AV_CO_PEER *p_peer, UINT8 *p_src_index) { int index; UINT8 codec_type; FUNC_TRACE(); /* Configure the codec type to look for */ codec_type = bta_av_co_cb.codec_cfg->id; for (index = 0; index < p_peer->num_sup_srcs; index++) { if (p_peer->srcs[index].codec_type == codec_type) { switch (bta_av_co_cb.codec_cfg->id) { case BTIF_AV_CODEC_SBC: if (p_src_index) *p_src_index = index; if (0 == bta_av_sbc_cfg_matches_cap((UINT8 *)p_peer->srcs[index].codec_caps, (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) { return TRUE; } break; default: APPL_TRACE_ERROR("peer_src_supports_codec: unsupported codec id %d", bta_av_co_cb.codec_cfg->id); return FALSE; break; } } } return FALSE; } /******************************************************************************* ** ** Function bta_av_co_audio_sink_supports_config ** ** Description Check if the media source supports a given configuration ** ** Returns TRUE if the media source supports this config, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_sink_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) { FUNC_TRACE(); switch (codec_type) { case BTA_AV_CODEC_SBC: if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_sink_caps)) { return FALSE; } break; default: APPL_TRACE_ERROR("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type); return FALSE; break; } return TRUE; } /******************************************************************************* ** ** Function bta_av_co_audio_media_supports_config ** ** Description Check if the media sink supports a given configuration ** ** Returns TRUE if the media source supports this config, FALSE otherwise ** *******************************************************************************/ static BOOLEAN bta_av_co_audio_media_supports_config(UINT8 codec_type, const UINT8 *p_codec_cfg) { FUNC_TRACE(); APPL_TRACE_DEBUG("%s codec_type = %x", __func__, codec_type); UINT16 codecId; UINT32 vendorId; UINT8* aptx_capabilities; switch (codec_type) { case BTA_AV_CODEC_SBC: if (bta_av_sbc_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_SBC_CIE *)&bta_av_co_sbc_caps)) { APPL_TRACE_DEBUG("%s SBC ",__func__); return FALSE; } break; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) case BTA_AV_CODEC_M24: if (bta_av_aac_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_AAC_CIE *)&bta_av_co_aac_caps)) { APPL_TRACE_DEBUG("%s AAC ",__func__); return FALSE; } break; #endif case A2D_NON_A2DP_MEDIA_CT: aptx_capabilities = &(((tBTA_AV_CO_SINK*)p_codec_cfg)->codec_caps[0]); codecId = ((tA2D_APTX_CIE*)(aptx_capabilities))->codecId; vendorId = ((tA2D_APTX_CIE*)(aptx_capabilities))->vendorId; APPL_TRACE_DEBUG("%s codecId = %d ", __func__, codecId); APPL_TRACE_DEBUG("%s vendorId = %x ", __func__, vendorId); if (codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_HD_VENDOR_ID) { APPL_TRACE_DEBUG("%s tA2D_APTX_CIE aptX HD", __func__); if (a2d_av_aptx_hd_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_APTX_HD_CIE *)&bta_av_co_aptx_hd_caps)) { APPL_TRACE_DEBUG("%s aptX HD", __func__); return FALSE; } break; } else if (codecId == A2D_APTX_CODEC_ID_BLUETOOTH && vendorId == A2D_APTX_VENDOR_ID) { APPL_TRACE_DEBUG("%s tA2D_APTX_CIE aptX", __func__); if (a2d_av_aptx_cfg_in_cap((UINT8 *)p_codec_cfg, (tA2D_APTX_CIE *)&bta_av_co_aptx_caps)) { APPL_TRACE_DEBUG("%s aptX", __func__); return FALSE; } break; } default: APPL_TRACE_ERROR("bta_av_co_audio_media_supports_config unsupported codec type %d", codec_type); return FALSE; break; } return TRUE; } /******************************************************************************* ** ** Function bta_av_co_audio_codec_supported ** ** Description Check if all opened connections are compatible with a codec ** configuration and content protection ** ** Returns TRUE if all opened devices support this codec, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_audio_codec_supported(tBTIF_STATUS *p_status) { UINT8 index; UINT8 snk_index; tBTA_AV_CO_PEER *p_peer; tBTA_AV_CO_SINK *p_sink; UINT8 codec_cfg[AVDT_CODEC_SIZE]; UINT8 num_protect = 0; #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) BOOLEAN cp_active; #endif UINT16 current_codec_id; current_codec_id = bta_av_co_cb.current_codec_id; UINT8 p_scb_codec_type = 0; FUNC_TRACE(); APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported"); /* Check AV feeding is supported */ *p_status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED; for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) { p_peer = &bta_av_co_cb.peers[index]; if (p_peer->opened) { if (bta_av_co_audio_peer_supports_codec(p_peer, &snk_index)) { p_sink = &p_peer->snks[snk_index]; /* Check that this sink is compatible with the CP */ if (!bta_av_co_audio_sink_supports_cp(p_sink)) { APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported sink %d of peer %d doesn't support cp", snk_index, index); *p_status = BTIF_ERROR_SRV_AV_CP_NOT_SUPPORTED; #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) if (!bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) { APPL_TRACE_DEBUG("%s index %d doesn't support codec", __func__, index); return FALSE; } return TRUE; #else return FALSE; #endif } /* Build the codec configuration for this sink */ if (bta_av_co_audio_codec_build_config(p_sink->codec_caps, codec_cfg)) { #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) /* Check if this sink supports SCMS */ cp_active = bta_av_co_audio_sink_has_scmst(p_sink); #endif APPL_TRACE_DEBUG("%s current_codec_id: %x", __func__, bta_av_co_cb.current_codec_id); APPL_TRACE_DEBUG("%s p_scb_codec_type: %x", __func__, p_scb_codec_type); p_scb_codec_type = bta_av_get_codec_type(); APPL_TRACE_DEBUG("%s p_scb_codec_type: %x", __func__, p_scb_codec_type); /* Check if this is a new configuration (new sink or new config) */ if ((p_sink != p_peer->p_snk) || (memcmp(codec_cfg, p_peer->codec_cfg, AVDT_CODEC_SIZE)) #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) || (p_peer->cp_active != cp_active) #endif ) { /* Save the new configuration */ p_peer->p_snk = p_sink; memcpy(p_peer->codec_cfg, codec_cfg, AVDT_CODEC_SIZE); #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) p_peer->cp_active = cp_active; if (p_peer->cp_active) { bta_av_co_cb.cp.active = TRUE; num_protect = BTA_AV_CP_INFO_LEN; } else { bta_av_co_cb.cp.active = FALSE; } #endif APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported call BTA_AvReconfig(x%x)", BTA_AV_CO_AUDIO_INDX_TO_HNDL(index)); BTA_AvReconfig(BTA_AV_CO_AUDIO_INDX_TO_HNDL(index), TRUE, p_sink->sep_info_idx, p_peer->codec_cfg, num_protect, (UINT8 *)bta_av_co_cp_scmst); } } } else { APPL_TRACE_DEBUG("bta_av_co_audio_codec_supported index %d doesn't support codec", index); return FALSE; } } } *p_status = BTIF_SUCCESS; return TRUE; } /******************************************************************************* ** ** Function bta_av_co_audio_codec_reset ** ** Description Reset the current codec configuration ** ** Returns void ** *******************************************************************************/ void bta_av_co_audio_codec_reset(void) { mutex_global_lock(); FUNC_TRACE(); /* Reset the current configuration to SBC */ bta_av_co_cb.codec_cfg_sbc.id = BTIF_AV_CODEC_SBC; if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_SBC_CIE *)&btif_av_sbc_default_config, bta_av_co_cb.codec_cfg_sbc.info) != A2D_SUCCESS) { APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldSbcInfo failed"); } else bta_av_co_cb.codec_cfg = &(bta_av_co_cb.codec_cfg_sbc); #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) /* Reset the current configuration to AAC */ bta_av_co_cb.codec_cfg_aac.id = BTIF_AV_CODEC_M24; if (A2D_BldAacInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_AAC_CIE *)&btif_av_aac_default_config, bta_av_co_cb.codec_cfg_aac.info) != A2D_SUCCESS) { APPL_TRACE_ERROR("bta_av_co_audio_codec_reset A2D_BldAacInfo failed"); } else bta_av_co_cb.codec_cfg = &(bta_av_co_cb.codec_cfg_sbc); #endif /* Reset the Current configuration to aptX */ bta_av_co_cb.codec_cfg_aptx.id = A2D_NON_A2DP_MEDIA_CT; if (A2D_BldAptxInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_APTX_CIE *)&btif_av_aptx_default_config, bta_av_co_cb.codec_cfg_aptx.info) != A2D_SUCCESS) APPL_TRACE_ERROR("%s A2D_BldAptxInfo failed", __func__); /* Reset the Current configuration to aptX HD */ bta_av_co_cb.codec_cfg_aptx_hd.id = A2D_NON_A2DP_MEDIA_CT; if (A2D_BldAptx_hdInfo(A2D_MEDIA_TYPE_AUDIO, (tA2D_APTX_HD_CIE *)&btif_av_aptx_hd_default_config, bta_av_co_cb.codec_cfg_aptx_hd.info) != A2D_SUCCESS) APPL_TRACE_ERROR("%s A2D_BldAptx_hdInfo failed", __func__); mutex_global_unlock(); } /******************************************************************************* ** ** Function bta_av_co_audio_set_codec ** ** Description Set the current codec configuration from the feeding type. ** This function is starting to modify the configuration, it ** should be protected. ** ** Returns TRUE if successful, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_audio_set_codec(const tBTIF_AV_MEDIA_FEEDINGS *p_feeding, tBTIF_STATUS *p_status) { tA2D_SBC_CIE sbc_config; tBTIF_AV_CODEC_INFO new_cfg_sbc; tA2D_APTX_CIE aptx_config; tBTIF_AV_CODEC_INFO new_cfg_aptx; tA2D_APTX_HD_CIE aptx_hd_config; tBTIF_AV_CODEC_INFO new_cfg_aptx_hd; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) tA2D_AAC_CIE aac_config; tBTIF_AV_CODEC_INFO new_cfg_aac; #endif FUNC_TRACE(); /* Check AV feeding is supported */ *p_status = BTIF_ERROR_SRV_AV_FEEDING_NOT_SUPPORTED; APPL_TRACE_DEBUG("bta_av_co_audio_set_codec cid=%d", p_feeding->format); /* Supported codecs */ switch (p_feeding->format) { case BTIF_AV_CODEC_PCM: new_cfg_sbc.id = BTIF_AV_CODEC_SBC; sbc_config = btif_av_sbc_default_config; if ((p_feeding->cfg.pcm.num_channel != 1) && (p_feeding->cfg.pcm.num_channel != 2)) { APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM channel number unsupported"); return FALSE; } if ((p_feeding->cfg.pcm.bit_per_sample != 8) && (p_feeding->cfg.pcm.bit_per_sample != 16) && (p_feeding->cfg.pcm.bit_per_sample != 32)) { APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM sample size unsupported"); return FALSE; } new_cfg_aptx.id = A2D_NON_A2DP_MEDIA_CT; aptx_config = btif_av_aptx_default_config; new_cfg_aptx_hd.id = A2D_NON_A2DP_MEDIA_CT; aptx_hd_config = btif_av_aptx_hd_default_config; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) new_cfg_aac.id = BTIF_AV_CODEC_M24; aac_config = btif_av_aac_default_config; #endif switch (p_feeding->cfg.pcm.sampling_freq) { case 8000: case 12000: case 16000: case 24000: case 32000: case 48000: sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_48; aptx_config.sampleRate = A2D_APTX_SAMPLERATE_48000; aptx_hd_config.sampleRate = A2D_APTX_HD_SAMPLERATE_48000; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) aac_config.samp_freq = A2D_AAC_IE_SAMP_FREQ_48000; #endif break; case 11025: case 22050: case 44100: sbc_config.samp_freq = A2D_SBC_IE_SAMP_FREQ_44; aptx_config.sampleRate = A2D_APTX_SAMPLERATE_44100; aptx_hd_config.sampleRate = A2D_APTX_HD_SAMPLERATE_44100; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) aac_config.samp_freq = A2D_AAC_IE_SAMP_FREQ_44100; #endif break; default: APPL_TRACE_ERROR("bta_av_co_audio_set_codec PCM sampling frequency unsupported"); return FALSE; break; } /* Build the codec config */ if (A2D_BldSbcInfo(A2D_MEDIA_TYPE_AUDIO, &sbc_config, new_cfg_sbc.info) != A2D_SUCCESS) { APPL_TRACE_ERROR("bta_av_co_audio_set_codec A2D_BldSbcInfo failed"); return FALSE; } if (A2D_BldAptxInfo(A2D_MEDIA_TYPE_AUDIO, &aptx_config, new_cfg_aptx.info) != A2D_SUCCESS) { APPL_TRACE_ERROR("%s A2D_BldAptxInfo failed", __func__); return FALSE; } if (A2D_BldAptx_hdInfo(A2D_MEDIA_TYPE_AUDIO, &aptx_hd_config, new_cfg_aptx_hd.info) != A2D_SUCCESS) { APPL_TRACE_ERROR("%s A2D_BldAptx_hdInfo failed", __func__); return FALSE; } #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) if (A2D_BldAacInfo(A2D_MEDIA_TYPE_AUDIO, &aac_config, new_cfg_aac.info) != A2D_SUCCESS) { APPL_TRACE_ERROR("%s A2D_BldAacInfo failed", __func__); return FALSE; } #endif break; default: APPL_TRACE_ERROR("bta_av_co_audio_set_codec Feeding format unsupported"); return FALSE; break; } /* The new config was correctly built. The default codec is set to be SBC */ bta_av_co_cb.codec_cfg_sbc = new_cfg_sbc; bta_av_co_cb.codec_cfg = &bta_av_co_cb.codec_cfg_sbc; bta_av_co_cb.codec_cfg_aptx= new_cfg_aptx; bta_av_co_cb.codec_cfg_aptx_hd = new_cfg_aptx_hd; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) bta_av_co_cb.codec_cfg_aac = new_cfg_aac; #endif /* Check all devices support it */ *p_status = BTIF_SUCCESS; return bta_av_co_audio_codec_supported(p_status); } UINT8 bta_av_select_codec(UINT8 hdl) { if (NULL == bta_av_co_cb.codec_cfg) { // Some circumstances - bta_av_co functions are called before // codec clock is initialised APPL_TRACE_ERROR("%s hdl = %d, no codec configured", __func__, hdl); return BTIF_AV_CODEC_NONE; } else { tBTA_AV_CO_PEER *p_peer; UINT8 index; APPL_TRACE_ERROR("%s hdl = %d",__func__,hdl); /* Retrieve the peer info */ p_peer = bta_av_co_get_peer(hdl); /* Fix for below KW Issue Pointer 'p_peer' returned from call to function 'bta_av_co_get_peer' at line 1993 may be NULL, will be passed to function and may be dereferenced there by passing argument 1 to function 'bta_av_co_audio_peer_supports_codec' at line 2001.*/ if (p_peer != NULL) { bta_av_co_audio_peer_supports_codec(p_peer,&index); } return bta_av_co_cb.codec_cfg->id; } } UINT8 bta_av_co_get_current_codec() { // Some circumstances - bta_av_co functions are called before codec clock is initialised if (NULL == bta_av_co_cb.codec_cfg) return BTIF_AV_CODEC_NONE; else return bta_av_co_cb.codec_cfg->id; } UINT8* bta_av_co_get_current_codecInfo() { // We assume that the configuration block is always valid when this is called. return &bta_av_co_cb.codec_cfg->info[0]; } /******************************************************************************* ** ** Function bta_av_co_audio_get_codec_config ** ** Description Retrieves the current codec configuration. In case of failure return ** the default SBC codec configuration. ** ** Returns TRUE if returned current codec config, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_audio_get_codec_config(UINT8 *p_config, UINT16 *p_minmtu, UINT8 type) { BOOLEAN result = FALSE; UINT8 index, jndex; tBTA_AV_CO_PEER *p_peer; tBTA_AV_CO_SINK *p_sink; tA2D_SBC_CIE *sbc_config; #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) tA2D_AAC_CIE *aac_config; #endif APPL_TRACE_EVENT("%s codec 0x%x", __func__, bta_av_co_cb.codec_cfg->id); /* Minimum MTU is by default very large */ *p_minmtu = 0xFFFF; mutex_global_lock(); if (type == BTIF_AV_CODEC_SBC) { APPL_TRACE_DEBUG("%s SBC", __func__); sbc_config = (tA2D_SBC_CIE *)p_config; if (A2D_ParsSbcInfo(sbc_config, bta_av_co_cb.codec_cfg_sbc.info, FALSE) == A2D_SUCCESS) result = TRUE; else memcpy((tA2D_SBC_CIE *) p_config, &btif_av_sbc_default_config, sizeof(tA2D_SBC_CIE)); } else if (type == A2D_NON_A2DP_MEDIA_CT && ((tA2D_APTX_CIE *)p_config)->vendorId == A2D_APTX_VENDOR_ID && ((tA2D_APTX_CIE *)p_config)->codecId == A2D_APTX_CODEC_ID_BLUETOOTH) { APPL_TRACE_DEBUG("%s aptX", __func__); tA2D_APTX_CIE *aptx_config = (tA2D_APTX_CIE *)p_config; if (A2D_ParsAptxInfo(aptx_config, bta_av_co_cb.codec_cfg_aptx.info, FALSE) == A2D_SUCCESS) result = TRUE; else memcpy((tA2D_APTX_CIE *) p_config, &btif_av_aptx_default_config, sizeof(tA2D_APTX_CIE)); } else if (type == A2D_NON_A2DP_MEDIA_CT && ((tA2D_APTX_HD_CIE *)p_config)->vendorId == A2D_APTX_HD_VENDOR_ID && ((tA2D_APTX_HD_CIE *)p_config)->codecId == A2D_APTX_HD_CODEC_ID_BLUETOOTH) { APPL_TRACE_DEBUG("%s aptX HD", __func__); tA2D_APTX_HD_CIE *aptx_hd_config = (tA2D_APTX_HD_CIE *)p_config; if (A2D_ParsAptx_hdInfo(aptx_hd_config, bta_av_co_cb.codec_cfg_aptx_hd.info, FALSE) == A2D_SUCCESS) result = TRUE; else memcpy((tA2D_APTX_HD_CIE *) p_config, &btif_av_aptx_hd_default_config, sizeof(tA2D_APTX_HD_CIE)); } else { APPL_TRACE_DEBUG("%s vendorId: %d codecId: %d\n", __func__, ((tA2D_APTX_CIE *)p_config)->vendorId, ((tA2D_APTX_CIE *)p_config)->codecId); } #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) if (type == BTIF_AV_CODEC_M24) { APPL_TRACE_DEBUG("%s AAC", __func__); aac_config = (tA2D_AAC_CIE *)p_config; if (A2D_ParsAacInfo(aac_config, bta_av_co_cb.codec_cfg_aac.info, FALSE) == A2D_SUCCESS) result = TRUE; else memcpy((tA2D_AAC_CIE *) p_config, &btif_av_aac_default_config, sizeof(tA2D_AAC_CIE)); } #endif for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) { p_peer = &bta_av_co_cb.peers[index]; if (p_peer->opened) { if (p_peer->mtu < *p_minmtu) *p_minmtu = p_peer->mtu; for (jndex = 0; jndex < p_peer->num_sup_snks; jndex++) { p_sink = &p_peer->snks[jndex]; if (type == BTIF_AV_CODEC_SBC && p_sink->codec_type == A2D_MEDIA_CT_SBC) { /* Update the bitpool boundaries of the current config */ sbc_config->min_bitpool = BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], sbc_config->min_bitpool); sbc_config->max_bitpool = BTA_AV_CO_MIN(p_sink->codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], sbc_config->max_bitpool); APPL_TRACE_EVENT("%s sink bitpool min %d, max %d", __func__, sbc_config->min_bitpool, sbc_config->max_bitpool); break; } } } } mutex_global_unlock(); return result; } /******************************************************************************* ** ** Function bta_av_co_audio_get_sbc_config ** ** Description Retrieves the SBC codec configuration. If the codec in use ** is not SBC, return the default SBC codec configuration. ** ** Returns TRUE if codec is SBC, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_audio_get_sbc_config(tA2D_SBC_CIE *p_sbc_config, UINT16 *p_minmtu) { BOOLEAN result = FALSE; UINT8 index, jndex; tBTA_AV_CO_PEER *p_peer; tBTA_AV_CO_SINK *p_sink; APPL_TRACE_EVENT("bta_av_co_cb.codec_cfg->id : codec 0x%x", bta_av_co_cb.codec_cfg->id); /* Minimum MTU is by default very large */ *p_minmtu = 0xFFFF; mutex_global_lock(); if (bta_av_co_cb.codec_cfg->id == BTIF_AV_CODEC_SBC) { if (A2D_ParsSbcInfo(p_sbc_config, bta_av_co_cb.codec_cfg->info, FALSE) == A2D_SUCCESS) { for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) { p_peer = &bta_av_co_cb.peers[index]; if (p_peer->opened) { APPL_TRACE_EVENT("%s on index= %d", __func__, index); if (p_peer->mtu < *p_minmtu) { *p_minmtu = p_peer->mtu; } for (jndex = 0; jndex < p_peer->num_sup_snks; jndex++) { p_sink = &p_peer->snks[jndex]; if (p_sink->codec_type == A2D_MEDIA_CT_SBC) { /* Update the bitpool boundaries of the current config */ APPL_TRACE_EVENT("%s Update the bitpool boundaries on index= %d", __func__, jndex); p_sbc_config->min_bitpool = BTA_AV_CO_MAX(p_sink->codec_caps[BTA_AV_CO_SBC_MIN_BITPOOL_OFF], p_sbc_config->min_bitpool); p_sbc_config->max_bitpool = BTA_AV_CO_MIN(p_sink->codec_caps[BTA_AV_CO_SBC_MAX_BITPOOL_OFF], p_sbc_config->max_bitpool); APPL_TRACE_EVENT("bta_av_co_audio_get_sbc_config : sink bitpool min %d, max %d", p_sbc_config->min_bitpool, p_sbc_config->max_bitpool); break; } } } } result = TRUE; } } if (!result) { /* Not SBC, still return the default values */ APPL_TRACE_EVENT("%s Not SBC, still return the default values", __func__); *p_sbc_config = btif_av_sbc_default_config; } mutex_global_unlock(); return result; } #if defined(AAC_ENCODER_INCLUDED) && (AAC_ENCODER_INCLUDED == TRUE) /******************************************************************************* ** ** Function bta_av_co_audio_get_aac_config ** ** Description Retrieves the AAC codec configuration. If the codec in use ** is not AAC, return the default AAC codec configuration. ** ** Returns TRUE if codec is AAC, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_audio_get_aac_config(tA2D_AAC_CIE *p_aac_config, UINT16 *p_minmtu) { BOOLEAN result = FALSE; UINT8 index; tBTA_AV_CO_PEER *p_peer; APPL_TRACE_EVENT("bta_av_co_cb.codec_cfg->id : codec 0x%x", bta_av_co_cb.codec_cfg->id); /* Minimum MTU is by default very large */ *p_minmtu = 0xFFFF; mutex_global_lock(); if (bta_av_co_cb.codec_cfg->id == BTIF_AV_CODEC_M24) { if (A2D_ParsAacInfo(p_aac_config, bta_av_co_cb.codec_cfg->info, FALSE) == A2D_SUCCESS) { for (index = 0; index < BTA_AV_CO_NUM_ELEMENTS(bta_av_co_cb.peers); index++) { p_peer = &bta_av_co_cb.peers[index]; if (p_peer->opened) { APPL_TRACE_EVENT("%s on index= %d", __func__, index); if (p_peer->mtu < *p_minmtu) { *p_minmtu = p_peer->mtu; } } } result = TRUE; } } if (!result) { /* Not AAC, still return the default values */ APPL_TRACE_EVENT("%s Not SBC, still return the default values", __func__); *p_aac_config = btif_av_aac_default_config; } mutex_global_unlock(); return result; } #endif /******************************************************************************* ** ** Function bta_av_co_audio_discard_config ** ** Description Discard the codec configuration of a connection ** ** Returns Nothing ** *******************************************************************************/ void bta_av_co_audio_discard_config(tBTA_AV_HNDL hndl) { tBTA_AV_CO_PEER *p_peer; FUNC_TRACE(); /* Find the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR("bta_av_co_audio_discard_config could not find peer entry"); return; } /* Reset the peer codec configuration */ bta_av_co_audio_peer_reset_config(p_peer); } /******************************************************************************* ** ** Function bta_av_co_init ** ** Description Initialization ** ** Returns Nothing ** *******************************************************************************/ void bta_av_co_init(void) { FUNC_TRACE(); /* Reset the control block */ memset(&bta_av_co_cb, 0, sizeof(bta_av_co_cb)); bta_av_co_cb.codec_cfg_setconfig = NULL; #if defined(BTA_AV_CO_CP_SCMS_T) && (BTA_AV_CO_CP_SCMS_T == TRUE) bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_NEVER); #else bta_av_co_cp_set_flag(BTA_AV_CP_SCMS_COPY_FREE); #endif /* Reset the current config */ bta_av_co_audio_codec_reset(); } /******************************************************************************* ** ** Function bta_av_co_peer_cp_supported ** ** Description Checks if the peer supports CP ** ** Returns TRUE if the peer supports CP ** *******************************************************************************/ BOOLEAN bta_av_co_peer_cp_supported(tBTA_AV_HNDL hndl) { tBTA_AV_CO_PEER *p_peer; tBTA_AV_CO_SINK *p_sink; UINT8 index; FUNC_TRACE(); /* Find the peer info */ p_peer = bta_av_co_get_peer(hndl); if (p_peer == NULL) { APPL_TRACE_ERROR("bta_av_co_peer_cp_supported could not find peer entry"); return FALSE; } for (index = 0; index < p_peer->num_sup_snks; index++) { p_sink = &p_peer->snks[index]; if (p_sink->codec_type == A2D_MEDIA_CT_SBC) { return bta_av_co_audio_sink_has_scmst(p_sink); } } APPL_TRACE_ERROR("bta_av_co_peer_cp_supported did not find SBC sink"); return FALSE; } /******************************************************************************* ** ** Function bta_av_co_get_remote_bitpool_pref ** ** Description Check if remote side did a setconfig within the limits ** of our exported bitpool range. If set we will set the ** remote preference. ** ** Returns TRUE if config set, FALSE otherwize ** *******************************************************************************/ BOOLEAN bta_av_co_get_remote_bitpool_pref(UINT8 *min, UINT8 *max) { /* check if remote peer did a set config */ if (bta_av_co_cb.codec_cfg_setconfig == NULL) return FALSE; *min = bta_av_co_cb.codec_cfg_setconfig->info[BTA_AV_CO_SBC_MIN_BITPOOL_OFF]; *max = bta_av_co_cb.codec_cfg_setconfig->info[BTA_AV_CO_SBC_MAX_BITPOOL_OFF]; return TRUE; } /******************************************************************************* ** ** Function bta_av_co_audio_is_offload_supported ** ** Description This function is called by AV to check if DUT is in offload ** mode. ** ** Returns TRUE if offload is enabled, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_audio_is_offload_supported(void) { return btif_av_is_offload_supported(); } /******************************************************************************* ** ** Function bta_av_co_audio_is_codec_supported ** ** Description This function is called by AV to check if corresponding ** codec is supported in offload mode. ** ** Returns TRUE if codec is supported in offload, FALSE otherwise ** *******************************************************************************/ BOOLEAN bta_av_co_audio_is_codec_supported(int codec) { return btif_av_is_codec_offload_supported(codec); }