1 /*
2 * Copyright (C) 2021 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 "gd/rust/topshim/hfp/hfp_shim.h"
18
19 #include "btif/include/btif_hf.h"
20 #include "gd/os/log.h"
21 #include "include/hardware/bt_hf.h"
22 #include "src/profiles/hfp.rs.h"
23 #include "types/raw_address.h"
24
25 namespace rusty = ::bluetooth::topshim::rust;
26
27 namespace bluetooth {
28 namespace topshim {
29 namespace rust {
30 namespace internal {
31 static HfpIntf* g_hfpif;
32
connection_state_cb(bluetooth::headset::bthf_connection_state_t state,RawAddress * addr)33 static void connection_state_cb(bluetooth::headset::bthf_connection_state_t state, RawAddress* addr) {
34 rusty::hfp_connection_state_callback(state, *addr);
35 }
36
audio_state_cb(bluetooth::headset::bthf_audio_state_t state,RawAddress * addr)37 static void audio_state_cb(bluetooth::headset::bthf_audio_state_t state, RawAddress* addr) {
38 rusty::hfp_audio_state_callback(state, *addr);
39 }
40
volume_update_cb(uint8_t volume,RawAddress * addr)41 static void volume_update_cb(uint8_t volume, RawAddress* addr) {
42 rusty::hfp_volume_update_callback(volume, *addr);
43 }
44
battery_level_update_cb(uint8_t battery_level,RawAddress * addr)45 static void battery_level_update_cb(uint8_t battery_level, RawAddress* addr) {
46 rusty::hfp_battery_level_update_callback(battery_level, *addr);
47 }
48
indicator_query_cb(RawAddress * addr)49 static void indicator_query_cb(RawAddress* addr) {
50 rusty::hfp_indicator_query_callback(*addr);
51 }
52
current_calls_query_cb(RawAddress * addr)53 static void current_calls_query_cb(RawAddress* addr) {
54 rusty::hfp_current_calls_query_callback(*addr);
55 }
56
answer_call_cb(RawAddress * addr)57 static void answer_call_cb(RawAddress* addr) {
58 rusty::hfp_answer_call_callback(*addr);
59 }
60
hangup_call_cb(RawAddress * addr)61 static void hangup_call_cb(RawAddress* addr) {
62 rusty::hfp_hangup_call_callback(*addr);
63 }
64
dial_call_cb(char * number,RawAddress * addr)65 static void dial_call_cb(char* number, RawAddress* addr) {
66 rusty::hfp_dial_call_callback(::rust::String{number}, *addr);
67 }
68
call_hold_cb(bluetooth::headset::bthf_chld_type_t chld,RawAddress * addr)69 static void call_hold_cb(bluetooth::headset::bthf_chld_type_t chld, RawAddress* addr) {
70 rusty::CallHoldCommand chld_rs;
71 switch (chld) {
72 case bluetooth::headset::BTHF_CHLD_TYPE_RELEASEHELD:
73 chld_rs = rusty::CallHoldCommand::ReleaseHeld;
74 break;
75 case bluetooth::headset::BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD:
76 chld_rs = rusty::CallHoldCommand::ReleaseActiveAcceptHeld;
77 break;
78 case bluetooth::headset::BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD:
79 chld_rs = rusty::CallHoldCommand::HoldActiveAcceptHeld;
80 break;
81 case bluetooth::headset::BTHF_CHLD_TYPE_ADDHELDTOCONF:
82 chld_rs = rusty::CallHoldCommand::AddHeldToConf;
83 break;
84 default:
85 ASSERT_LOG(false, "Unhandled enum value from C++");
86 }
87 rusty::hfp_call_hold_callback(chld_rs, *addr);
88 }
89
from_rust_call_state(rusty::CallState state)90 static headset::bthf_call_state_t from_rust_call_state(rusty::CallState state) {
91 switch (state) {
92 case rusty::CallState::Idle:
93 return headset::BTHF_CALL_STATE_IDLE;
94 case rusty::CallState::Incoming:
95 return headset::BTHF_CALL_STATE_INCOMING;
96 case rusty::CallState::Dialing:
97 return headset::BTHF_CALL_STATE_DIALING;
98 case rusty::CallState::Alerting:
99 return headset::BTHF_CALL_STATE_ALERTING;
100 case rusty::CallState::Active:
101 return headset::BTHF_CALL_STATE_ACTIVE;
102 case rusty::CallState::Held:
103 return headset::BTHF_CALL_STATE_HELD;
104 default:
105 ASSERT_LOG(false, "Unhandled enum value from Rust");
106 }
107 }
108 } // namespace internal
109
110 class DBusHeadsetCallbacks : public headset::Callbacks {
111 public:
GetInstance(headset::Interface * headset)112 static Callbacks* GetInstance(headset::Interface* headset) {
113 static Callbacks* instance = new DBusHeadsetCallbacks(headset);
114 return instance;
115 }
116
DBusHeadsetCallbacks(headset::Interface * headset)117 DBusHeadsetCallbacks(headset::Interface* headset) : headset_(headset){};
118
119 // headset::Callbacks
ConnectionStateCallback(headset::bthf_connection_state_t state,RawAddress * bd_addr)120 void ConnectionStateCallback(headset::bthf_connection_state_t state, RawAddress* bd_addr) override {
121 LOG_INFO("ConnectionStateCallback from %s", ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
122 topshim::rust::internal::connection_state_cb(state, bd_addr);
123 }
124
AudioStateCallback(headset::bthf_audio_state_t state,RawAddress * bd_addr)125 void AudioStateCallback(headset::bthf_audio_state_t state, RawAddress* bd_addr) override {
126 LOG_INFO("AudioStateCallback %u from %s", state, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
127 topshim::rust::internal::audio_state_cb(state, bd_addr);
128 }
129
VoiceRecognitionCallback(headset::bthf_vr_state_t state,RawAddress * bd_addr)130 void VoiceRecognitionCallback(
131 [[maybe_unused]] headset::bthf_vr_state_t state, [[maybe_unused]] RawAddress* bd_addr) override {}
132
AnswerCallCallback(RawAddress * bd_addr)133 void AnswerCallCallback(RawAddress* bd_addr) override {
134 topshim::rust::internal::answer_call_cb(bd_addr);
135 }
136
HangupCallCallback(RawAddress * bd_addr)137 void HangupCallCallback(RawAddress* bd_addr) override {
138 topshim::rust::internal::hangup_call_cb(bd_addr);
139 }
140
VolumeControlCallback(headset::bthf_volume_type_t type,int volume,RawAddress * bd_addr)141 void VolumeControlCallback(headset::bthf_volume_type_t type, int volume, RawAddress* bd_addr) override {
142 if (type != headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK || volume < 0) return;
143 if (volume > 15) volume = 15;
144 LOG_INFO("VolumeControlCallback %d from %s", volume, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
145 topshim::rust::internal::volume_update_cb(volume, bd_addr);
146 }
147
DialCallCallback(char * number,RawAddress * bd_addr)148 void DialCallCallback(char* number, RawAddress* bd_addr) override {
149 topshim::rust::internal::dial_call_cb(number, bd_addr);
150 }
151
DtmfCmdCallback(char tone,RawAddress * bd_addr)152 void DtmfCmdCallback([[maybe_unused]] char tone, [[maybe_unused]] RawAddress* bd_addr) override {}
153
NoiseReductionCallback(headset::bthf_nrec_t nrec,RawAddress * bd_addr)154 void NoiseReductionCallback(
155 [[maybe_unused]] headset::bthf_nrec_t nrec, [[maybe_unused]] RawAddress* bd_addr) override {}
156
WbsCallback(headset::bthf_wbs_config_t wbs,RawAddress * addr)157 void WbsCallback(headset::bthf_wbs_config_t wbs, RawAddress* addr) override {
158 LOG_INFO("WbsCallback %d from %s", wbs, ADDRESS_TO_LOGGABLE_CSTR(*addr));
159 rusty::hfp_wbs_caps_update_callback(wbs == headset::BTHF_WBS_YES, *addr);
160 }
161
SwbCallback(headset::bthf_swb_config_t swb,RawAddress * addr)162 void SwbCallback(headset::bthf_swb_config_t swb, RawAddress* addr) override {
163 LOG_INFO("SwbCallback %d from %s", swb, ADDRESS_TO_LOGGABLE_CSTR(*addr));
164 rusty::hfp_swb_caps_update_callback(swb == headset::BTHF_SWB_YES, *addr);
165 }
166
AtChldCallback(headset::bthf_chld_type_t chld,RawAddress * bd_addr)167 void AtChldCallback(headset::bthf_chld_type_t chld, RawAddress* bd_addr) override {
168 topshim::rust::internal::call_hold_cb(chld, bd_addr);
169 }
170
AtCnumCallback(RawAddress * bd_addr)171 void AtCnumCallback(RawAddress* bd_addr) override {
172 // Send an OK response to HF to indicate that we have no subscriber info.
173 // This is mandatory support for passing HFP/AG/NUM/BV-01-I.
174 headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
175 }
176
AtCindCallback(RawAddress * bd_addr)177 void AtCindCallback(RawAddress* bd_addr) override {
178 topshim::rust::internal::indicator_query_cb(bd_addr);
179 }
180
AtCopsCallback(RawAddress * bd_addr)181 void AtCopsCallback(RawAddress* bd_addr) override {
182 LOG_WARN("Respond +COPS: 0 to AT+COPS? from %s",
183 ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
184 headset_->CopsResponse("", bd_addr);
185 }
186
AtClccCallback(RawAddress * bd_addr)187 void AtClccCallback(RawAddress* bd_addr) override {
188 topshim::rust::internal::current_calls_query_cb(bd_addr);
189 }
190
UnknownAtCallback(char * at_string,RawAddress * bd_addr)191 void UnknownAtCallback(char* at_string, RawAddress* bd_addr) override {
192 LOG_WARN("Reply Error to UnknownAtCallback:%s", at_string);
193 headset_->AtResponse(headset::BTHF_AT_RESPONSE_ERROR, 0, bd_addr);
194 }
195
KeyPressedCallback(RawAddress * bd_addr)196 void KeyPressedCallback([[maybe_unused]] RawAddress* bd_addr) override {}
197
AtBindCallback(char * at_string,RawAddress * bd_addr)198 void AtBindCallback(char* at_string, RawAddress* bd_addr) override {
199 LOG_WARN(
200 "AT+BIND %s from addr %s: Bluetooth HF Indicators is not supported.",
201 at_string,
202 ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
203 }
204
AtBievCallback(headset::bthf_hf_ind_type_t ind_id,int ind_value,RawAddress * bd_addr)205 void AtBievCallback(headset::bthf_hf_ind_type_t ind_id, int ind_value, RawAddress* bd_addr) override {
206 switch (ind_id) {
207 case headset::bthf_hf_ind_type_t::BTHF_HF_IND_ENHANCED_DRIVER_SAFETY:
208 // We don't do anything with this but we do know what it is, send OK.
209 headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
210 break;
211 case headset::bthf_hf_ind_type_t::BTHF_HF_IND_BATTERY_LEVEL_STATUS:
212 topshim::rust::internal::battery_level_update_cb(ind_value, bd_addr);
213 headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
214 break;
215 default:
216 LOG_WARN(
217 "AT+BIEV indicator %i with value %i from addr %s",
218 ind_id,
219 ind_value,
220 ADDRESS_TO_LOGGABLE_CSTR(*bd_addr) );
221 return;
222 }
223 }
224
AtBiaCallback(bool service,bool roam,bool signal,bool battery,RawAddress * bd_addr)225 void AtBiaCallback(bool service, bool roam, bool signal, bool battery, RawAddress* bd_addr) override {
226 LOG_WARN("AT+BIA=,,%d,%d,%d,%d,from addr %s", service, signal, roam,
227 battery, ADDRESS_TO_LOGGABLE_CSTR(*bd_addr));
228 }
229
230 private:
231 headset::Interface* headset_;
232 };
233
init()234 int HfpIntf::init() {
235 return intf_->Init(DBusHeadsetCallbacks::GetInstance(intf_), 1, false);
236 }
237
connect(RawAddress addr)238 uint32_t HfpIntf::connect(RawAddress addr) {
239 return intf_->Connect(&addr);
240 }
241
connect_audio(RawAddress addr,bool sco_offload,bool force_cvsd)242 int HfpIntf::connect_audio(RawAddress addr, bool sco_offload, bool force_cvsd) {
243 intf_->SetScoOffloadEnabled(sco_offload);
244 return intf_->ConnectAudio(&addr, force_cvsd);
245 }
246
set_active_device(RawAddress addr)247 int HfpIntf::set_active_device(RawAddress addr) {
248 return intf_->SetActiveDevice(&addr);
249 }
250
set_volume(int8_t volume,RawAddress addr)251 int HfpIntf::set_volume(int8_t volume, RawAddress addr) {
252 return intf_->VolumeControl(headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK, volume, &addr);
253 }
254
disconnect(RawAddress addr)255 uint32_t HfpIntf::disconnect(RawAddress addr) {
256 return intf_->Disconnect(&addr);
257 }
258
disconnect_audio(RawAddress addr)259 int HfpIntf::disconnect_audio(RawAddress addr) {
260 return intf_->DisconnectAudio(&addr);
261 }
262
device_status_notification(TelephonyDeviceStatus status,RawAddress addr)263 uint32_t HfpIntf::device_status_notification(TelephonyDeviceStatus status, RawAddress addr) {
264 return intf_->DeviceStatusNotification(
265 status.network_available ? headset::BTHF_NETWORK_STATE_AVAILABLE
266 : headset::BTHF_NETWORK_STATE_NOT_AVAILABLE,
267 status.roaming ? headset::BTHF_SERVICE_TYPE_ROAMING : headset::BTHF_SERVICE_TYPE_HOME,
268 status.signal_strength,
269 status.battery_level,
270 &addr);
271 }
272
indicator_query_response(TelephonyDeviceStatus device_status,PhoneState phone_state,RawAddress addr)273 uint32_t HfpIntf::indicator_query_response(
274 TelephonyDeviceStatus device_status, PhoneState phone_state, RawAddress addr) {
275 return intf_->CindResponse(
276 device_status.network_available ? 1 : 0,
277 phone_state.num_active,
278 phone_state.num_held,
279 topshim::rust::internal::from_rust_call_state(phone_state.state),
280 device_status.signal_strength,
281 device_status.roaming ? 1 : 0,
282 device_status.battery_level,
283 &addr);
284 }
285
current_calls_query_response(const::rust::Vec<CallInfo> & call_list,RawAddress addr)286 uint32_t HfpIntf::current_calls_query_response(
287 const ::rust::Vec<CallInfo>& call_list, RawAddress addr) {
288 for (const auto& c : call_list) {
289 std::string number{c.number};
290 intf_->ClccResponse(
291 c.index,
292 c.dir_incoming ? headset::BTHF_CALL_DIRECTION_INCOMING
293 : headset::BTHF_CALL_DIRECTION_OUTGOING,
294 topshim::rust::internal::from_rust_call_state(c.state),
295 /*mode=*/headset::BTHF_CALL_TYPE_VOICE,
296 /*multi_party=*/headset::BTHF_CALL_MPTY_TYPE_SINGLE,
297 number.c_str(),
298 /*type=*/headset::BTHF_CALL_ADDRTYPE_UNKNOWN,
299 &addr);
300 }
301
302 // NULL termination (Completes response)
303 return intf_->ClccResponse(
304 /*index=*/0,
305 /*dir=*/(headset::bthf_call_direction_t)0,
306 /*state=*/(headset::bthf_call_state_t)0,
307 /*mode=*/(headset::bthf_call_mode_t)0,
308 /*multi_party=*/(headset::bthf_call_mpty_type_t)0,
309 /*number=*/"",
310 /*type=*/(headset::bthf_call_addrtype_t)0,
311 &addr);
312 }
313
phone_state_change(PhoneState phone_state,const::rust::String & number_rs,RawAddress addr)314 uint32_t HfpIntf::phone_state_change(
315 PhoneState phone_state, const ::rust::String& number_rs, RawAddress addr) {
316 std::string number{number_rs};
317 return intf_->PhoneStateChange(
318 phone_state.num_active,
319 phone_state.num_held,
320 topshim::rust::internal::from_rust_call_state(phone_state.state),
321 number.c_str(),
322 /*type=*/(headset::bthf_call_addrtype_t)0,
323 /*name=*/"",
324 &addr);
325 }
326
simple_at_response(bool ok,RawAddress addr)327 uint32_t HfpIntf::simple_at_response(bool ok, RawAddress addr) {
328 return intf_->AtResponse(
329 (ok ? headset::BTHF_AT_RESPONSE_OK : headset::BTHF_AT_RESPONSE_ERROR), 0, &addr);
330 }
331
cleanup()332 void HfpIntf::cleanup() {}
333
GetHfpProfile(const unsigned char * btif)334 std::unique_ptr<HfpIntf> GetHfpProfile(const unsigned char* btif) {
335 if (internal::g_hfpif) std::abort();
336
337 const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
338
339 auto hfpif = std::make_unique<HfpIntf>(const_cast<headset::Interface*>(
340 reinterpret_cast<const headset::Interface*>(btif_->get_profile_interface("handsfree"))));
341 internal::g_hfpif = hfpif.get();
342
343 return hfpif;
344 }
345
346 } // namespace rust
347 } // namespace topshim
348 } // namespace bluetooth
349