1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "bta_ag_swb_aptx.h"
18
19 #include <android_bluetooth_sysprop.h>
20 #include <bluetooth/log.h>
21 #include <com_android_bluetooth_flags.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include "bta/ag/bta_ag_int.h"
26 #include "common/strings.h"
27 #include "stack/btm/btm_sco_hfp_hal.h"
28 #include "stack/include/btm_api_types.h"
29
30 using namespace bluetooth;
31
is_hfp_aptx_voice_enabled()32 bool is_hfp_aptx_voice_enabled() {
33 return com::android::bluetooth::flags::hfp_codec_aptx_voice() &&
34 GET_SYSPROP(Hfp, codec_aptx_voice, false);
35 }
36
37 static bool aptx_swb_codec_status;
38
get_lc3_swb_codec_status(RawAddress * bd_addr)39 static bool get_lc3_swb_codec_status(RawAddress* bd_addr) {
40 uint16_t p_scb_idx = bta_ag_idx_by_bdaddr(bd_addr);
41 tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(p_scb_idx);
42 if (p_scb != NULL) {
43 return (hfp_hal_interface::get_swb_supported() &&
44 (p_scb->peer_codecs & BTM_SCO_CODEC_LC3) &&
45 !(p_scb->disabled_codecs & BTM_SCO_CODEC_LC3));
46 }
47 return false;
48 }
49
get_aptx_swb_codec_status()50 static bool get_aptx_swb_codec_status() {
51 if (is_hfp_aptx_voice_enabled()) {
52 return aptx_swb_codec_status;
53 }
54 return false;
55 }
56
get_swb_codec_status(bluetooth::headset::bthf_swb_codec_t swb_codec,RawAddress * bd_addr)57 bool get_swb_codec_status(bluetooth::headset::bthf_swb_codec_t swb_codec,
58 RawAddress* bd_addr) {
59 bool status = false;
60 switch (swb_codec) {
61 case bluetooth::headset::BTHF_SWB_CODEC_LC3:
62 status = get_lc3_swb_codec_status(bd_addr);
63 log::verbose("LC3 SWB status={}", status);
64 break;
65 case bluetooth::headset::BTHF_SWB_CODEC_VENDOR_APTX:
66 status = get_aptx_swb_codec_status();
67 log::verbose("AptX SWB status={}", status);
68 break;
69 default:
70 log::error("Unknown codec: {}", (int)swb_codec);
71 break;
72 }
73 return status;
74 }
75
enable_aptx_swb_codec(bool enable,RawAddress * bd_addr)76 bt_status_t enable_aptx_swb_codec(bool enable, RawAddress* bd_addr) {
77 if (is_hfp_aptx_voice_enabled() &&
78 (get_lc3_swb_codec_status(bd_addr) == false)) {
79 log::verbose("enable={}", enable);
80 aptx_swb_codec_status = enable;
81 return BT_STATUS_SUCCESS;
82 }
83 return BT_STATUS_FAIL;
84 }
85
bta_ag_swb_handle_vs_at_events(tBTA_AG_SCB * p_scb,uint16_t cmd,int16_t int_arg,tBTA_AG_VAL * val)86 void bta_ag_swb_handle_vs_at_events(tBTA_AG_SCB* p_scb, uint16_t cmd,
87 int16_t int_arg, tBTA_AG_VAL* val) {
88 switch (cmd) {
89 case BTA_AG_AT_QAC_EVT:
90 if (!get_swb_codec_status(bluetooth::headset::BTHF_SWB_CODEC_VENDOR_APTX,
91 &p_scb->peer_addr)) {
92 bta_ag_send_qac(p_scb, NULL);
93 break;
94 }
95 log::verbose("BTA_AG_AT_QAC_EVT");
96 p_scb->codec_updated = true;
97 if (p_scb->peer_codecs & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK) {
98 p_scb->sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0;
99 } else if (p_scb->peer_codecs & BTM_SCO_CODEC_MSBC) {
100 p_scb->sco_codec = UUID_CODEC_MSBC;
101 }
102 bta_ag_send_qac(p_scb, NULL);
103 log::verbose("Received AT+QAC, updating sco codec to SWB: {}",
104 p_scb->sco_codec);
105 val->num = p_scb->peer_codecs;
106 break;
107 case BTA_AG_AT_QCS_EVT: {
108 tBTA_AG_PEER_CODEC codec_type, codec_sent;
109 alarm_cancel(p_scb->codec_negotiation_timer);
110
111 log::verbose("BTA_AG_AT_QCS_EVT int_arg={}", int_arg);
112 switch (int_arg) {
113 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q0:
114 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0;
115 break;
116 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q1:
117 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q1;
118 break;
119 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q2:
120 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q2;
121 break;
122 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q3:
123 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q3;
124 break;
125 default:
126 log::error("Unknown codec_uuid {}", int_arg);
127 p_scb->is_aptx_swb_codec = false;
128 codec_type = BTM_SCO_CODEC_MSBC;
129 p_scb->codec_fallback = true;
130 p_scb->sco_codec = BTM_SCO_CODEC_MSBC;
131 break;
132 }
133
134 if (p_scb->codec_fallback) {
135 codec_sent = BTM_SCO_CODEC_MSBC;
136 } else {
137 codec_sent = p_scb->sco_codec;
138 }
139
140 bta_ag_sco_codec_nego(p_scb, codec_type == codec_sent);
141
142 /* send final codec info to callback */
143 val->num = codec_sent;
144 break;
145 }
146 }
147 }
148
bta_ag_parse_qac(char * p_s)149 tBTA_AG_PEER_CODEC bta_ag_parse_qac(char* p_s) {
150 tBTA_AG_PEER_CODEC retval = BTM_SCO_CODEC_NONE;
151 tBTA_AG_SCO_APTX_SWB_SETTINGS codec_mode =
152 BTA_AG_SCO_APTX_SWB_SETTINGS_UNKNOWN;
153
154 auto codec_modes =
155 bluetooth::common::StringSplit(std::string(p_s), ",", SWB_CODECS_NUMBER);
156 for (auto& codec_mode_str : codec_modes) {
157 if (!std::isdigit(*codec_mode_str.c_str())) continue;
158 codec_mode = static_cast<tBTA_AG_SCO_APTX_SWB_SETTINGS>(
159 std::atoi(codec_mode_str.c_str()));
160 switch (codec_mode) {
161 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q0:
162 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK;
163 break;
164 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q1:
165 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK;
166 break;
167 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q2:
168 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK;
169 break;
170 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q3:
171 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK;
172 break;
173 default:
174 log::verbose("Unknown Codec UUID({}) received", codec_mode);
175 break;
176 }
177 }
178 return (retval);
179 }
180