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 <string.h>
22
23 #include <cctype>
24 #include <cstdint>
25 #include <cstdlib>
26 #include <string>
27
28 #include "bta/ag/bta_ag_int.h"
29 #include "bta_ag_api.h"
30 #include "common/strings.h"
31 #include "hardware/bluetooth.h"
32 #include "hardware/bt_hf.h"
33 #include "osi/include/alarm.h"
34 #include "stack/btm/btm_sco_hfp_hal.h"
35 #include "stack/include/btm_api_types.h"
36 #include "types/raw_address.h"
37
38 using namespace bluetooth;
39
is_hfp_aptx_voice_enabled()40 bool is_hfp_aptx_voice_enabled() {
41 return android::sysprop::bluetooth::Hfp::codec_aptx_voice().value_or(false);
42 }
43
44 static bool aptx_swb_codec_status;
45
get_lc3_swb_codec_status(RawAddress * bd_addr)46 static bool get_lc3_swb_codec_status(RawAddress* bd_addr) {
47 uint16_t p_scb_idx = bta_ag_idx_by_bdaddr(bd_addr);
48 tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(p_scb_idx);
49 if (p_scb != NULL) {
50 return hfp_hal_interface::get_swb_supported() && (p_scb->peer_codecs & BTM_SCO_CODEC_LC3) &&
51 !(p_scb->disabled_codecs & BTM_SCO_CODEC_LC3);
52 }
53 return false;
54 }
55
get_aptx_swb_codec_status()56 static bool get_aptx_swb_codec_status() {
57 if (is_hfp_aptx_voice_enabled()) {
58 return aptx_swb_codec_status;
59 }
60 return false;
61 }
62
get_swb_codec_status(bluetooth::headset::bthf_swb_codec_t swb_codec,RawAddress * bd_addr)63 bool get_swb_codec_status(bluetooth::headset::bthf_swb_codec_t swb_codec, RawAddress* bd_addr) {
64 bool status = false;
65 switch (swb_codec) {
66 case bluetooth::headset::BTHF_SWB_CODEC_LC3:
67 status = get_lc3_swb_codec_status(bd_addr);
68 log::verbose("LC3 SWB status={}", status);
69 break;
70 case bluetooth::headset::BTHF_SWB_CODEC_VENDOR_APTX:
71 status = get_aptx_swb_codec_status();
72 log::verbose("AptX SWB status={}", status);
73 break;
74 default:
75 log::error("Unknown codec: {}", (int)swb_codec);
76 break;
77 }
78 return status;
79 }
80
enable_aptx_swb_codec(bool enable,RawAddress * bd_addr)81 bt_status_t enable_aptx_swb_codec(bool enable, RawAddress* bd_addr) {
82 if (is_hfp_aptx_voice_enabled() && (get_lc3_swb_codec_status(bd_addr) == false)) {
83 log::verbose("enable={}", enable);
84 aptx_swb_codec_status = enable;
85 return BT_STATUS_SUCCESS;
86 }
87 return BT_STATUS_FAIL;
88 }
89
bta_ag_swb_handle_vs_at_events(tBTA_AG_SCB * p_scb,uint16_t cmd,int16_t int_arg,tBTA_AG_VAL * val)90 void bta_ag_swb_handle_vs_at_events(tBTA_AG_SCB* p_scb, uint16_t cmd, int16_t int_arg,
91 tBTA_AG_VAL* val) {
92 switch (cmd) {
93 case BTA_AG_AT_QAC_EVT:
94 if (!get_swb_codec_status(bluetooth::headset::BTHF_SWB_CODEC_VENDOR_APTX,
95 &p_scb->peer_addr)) {
96 bta_ag_send_qac(p_scb);
97 break;
98 }
99 log::verbose("BTA_AG_AT_QAC_EVT");
100 p_scb->codec_updated = true;
101 if (p_scb->peer_codecs & BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK) {
102 p_scb->sco_codec = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0;
103 } else if (p_scb->peer_codecs & BTM_SCO_CODEC_MSBC) {
104 p_scb->sco_codec = BTM_SCO_CODEC_MSBC;
105 }
106 bta_ag_send_qac(p_scb);
107 log::verbose("Received AT+QAC, updating sco codec to SWB: {}", p_scb->sco_codec);
108 val->num = p_scb->peer_codecs;
109 break;
110 case BTA_AG_AT_QCS_EVT: {
111 tBTA_AG_PEER_CODEC codec_type, codec_sent;
112 alarm_cancel(p_scb->codec_negotiation_timer);
113
114 log::verbose("BTA_AG_AT_QCS_EVT int_arg={}", int_arg);
115 switch (int_arg) {
116 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q0:
117 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q0;
118 break;
119 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q1:
120 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q1;
121 break;
122 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q2:
123 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q2;
124 break;
125 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q3:
126 codec_type = BTA_AG_SCO_APTX_SWB_SETTINGS_Q3;
127 break;
128 default:
129 log::error("Unknown codec_uuid {}", int_arg);
130 p_scb->is_aptx_swb_codec = false;
131 codec_type = BTM_SCO_CODEC_MSBC;
132 p_scb->codec_fallback = true;
133 p_scb->sco_codec = BTM_SCO_CODEC_MSBC;
134 break;
135 }
136
137 if (p_scb->codec_fallback) {
138 codec_sent = BTM_SCO_CODEC_MSBC;
139 } else {
140 codec_sent = p_scb->sco_codec;
141 }
142
143 bta_ag_sco_codec_nego(p_scb, codec_type == codec_sent);
144
145 /* send final codec info to callback */
146 val->num = codec_sent;
147 break;
148 }
149 }
150 }
151
bta_ag_parse_qac(char * p_s)152 tBTA_AG_PEER_CODEC bta_ag_parse_qac(char* p_s) {
153 tBTA_AG_PEER_CODEC retval = BTM_SCO_CODEC_NONE;
154 tBTA_AG_SCO_APTX_SWB_SETTINGS codec_mode = BTA_AG_SCO_APTX_SWB_SETTINGS_UNKNOWN;
155
156 auto codec_modes = bluetooth::common::StringSplit(std::string(p_s), ",", SWB_CODECS_NUMBER);
157 for (auto& codec_mode_str : codec_modes) {
158 if (!std::isdigit(*codec_mode_str.c_str())) {
159 continue;
160 }
161 codec_mode = static_cast<tBTA_AG_SCO_APTX_SWB_SETTINGS>(std::atoi(codec_mode_str.c_str()));
162 switch (codec_mode) {
163 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q0:
164 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q0_MASK;
165 break;
166 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q1:
167 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q1_MASK;
168 break;
169 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q2:
170 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q2_MASK;
171 break;
172 case BTA_AG_SCO_APTX_SWB_SETTINGS_Q3:
173 retval |= BTA_AG_SCO_APTX_SWB_SETTINGS_Q3_MASK;
174 break;
175 default:
176 log::verbose("Unknown Codec UUID({}) received", codec_mode);
177 break;
178 }
179 }
180 return retval;
181 }
182