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