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 "rust/topshim/hfp/hfp_shim.h"
18 
19 #include <bluetooth/log.h>
20 
21 #include "btif/include/btif_hf.h"
22 #include "common/strings.h"
23 #include "device/include/interop.h"
24 #include "include/hardware/bt_hf.h"
25 #include "os/log.h"
26 #include "src/profiles/hfp.rs.h"
27 #include "types/raw_address.h"
28 
29 namespace rusty = ::bluetooth::topshim::rust;
30 
31 namespace bluetooth {
32 namespace topshim {
33 namespace rust {
34 namespace internal {
35 static HfpIntf* g_hfpif;
36 
connection_state_cb(bluetooth::headset::bthf_connection_state_t state,RawAddress * addr)37 static void connection_state_cb(bluetooth::headset::bthf_connection_state_t state, RawAddress* addr) {
38   rusty::hfp_connection_state_callback(state, *addr);
39 }
40 
audio_state_cb(bluetooth::headset::bthf_audio_state_t state,RawAddress * addr)41 static void audio_state_cb(bluetooth::headset::bthf_audio_state_t state, RawAddress* addr) {
42   rusty::hfp_audio_state_callback(state, *addr);
43 }
44 
volume_update_cb(uint8_t volume,RawAddress * addr)45 static void volume_update_cb(uint8_t volume, RawAddress* addr) {
46   rusty::hfp_volume_update_callback(volume, *addr);
47 }
48 
mic_volume_update_cb(uint8_t volume,RawAddress * addr)49 static void mic_volume_update_cb(uint8_t volume, RawAddress* addr) {
50   rusty::hfp_mic_volume_update_callback(volume, *addr);
51 }
52 
vendor_specific_at_command_cb(char * at_string,RawAddress * addr)53 static void vendor_specific_at_command_cb(char* at_string, RawAddress* addr) {
54   rusty::hfp_vendor_specific_at_command_callback(::rust::String{at_string}, *addr);
55 }
56 
battery_level_update_cb(uint8_t battery_level,RawAddress * addr)57 static void battery_level_update_cb(uint8_t battery_level, RawAddress* addr) {
58   rusty::hfp_battery_level_update_callback(battery_level, *addr);
59 }
60 
indicator_query_cb(RawAddress * addr)61 static void indicator_query_cb(RawAddress* addr) {
62   rusty::hfp_indicator_query_callback(*addr);
63 }
64 
current_calls_query_cb(RawAddress * addr)65 static void current_calls_query_cb(RawAddress* addr) {
66   rusty::hfp_current_calls_query_callback(*addr);
67 }
68 
answer_call_cb(RawAddress * addr)69 static void answer_call_cb(RawAddress* addr) {
70   rusty::hfp_answer_call_callback(*addr);
71 }
72 
hangup_call_cb(RawAddress * addr)73 static void hangup_call_cb(RawAddress* addr) {
74   rusty::hfp_hangup_call_callback(*addr);
75 }
76 
dial_call_cb(char * number,RawAddress * addr)77 static void dial_call_cb(char* number, RawAddress* addr) {
78   rusty::hfp_dial_call_callback(::rust::String{number}, *addr);
79 }
80 
call_hold_cb(bluetooth::headset::bthf_chld_type_t chld,RawAddress * addr)81 static void call_hold_cb(bluetooth::headset::bthf_chld_type_t chld, RawAddress* addr) {
82   rusty::CallHoldCommand chld_rs;
83   switch (chld) {
84     case bluetooth::headset::BTHF_CHLD_TYPE_RELEASEHELD:
85       chld_rs = rusty::CallHoldCommand::ReleaseHeld;
86       break;
87     case bluetooth::headset::BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD:
88       chld_rs = rusty::CallHoldCommand::ReleaseActiveAcceptHeld;
89       break;
90     case bluetooth::headset::BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD:
91       chld_rs = rusty::CallHoldCommand::HoldActiveAcceptHeld;
92       break;
93     case bluetooth::headset::BTHF_CHLD_TYPE_ADDHELDTOCONF:
94       chld_rs = rusty::CallHoldCommand::AddHeldToConf;
95       break;
96     default:
97       log::fatal("Unhandled enum value from C++");
98   }
99   rusty::hfp_call_hold_callback(chld_rs, *addr);
100 }
101 
from_rust_call_state(rusty::CallState state)102 static headset::bthf_call_state_t from_rust_call_state(rusty::CallState state) {
103   switch (state) {
104     case rusty::CallState::Idle:
105       return headset::BTHF_CALL_STATE_IDLE;
106     case rusty::CallState::Incoming:
107       return headset::BTHF_CALL_STATE_INCOMING;
108     case rusty::CallState::Dialing:
109       return headset::BTHF_CALL_STATE_DIALING;
110     case rusty::CallState::Alerting:
111       return headset::BTHF_CALL_STATE_ALERTING;
112     case rusty::CallState::Active:
113       return headset::BTHF_CALL_STATE_ACTIVE;
114     case rusty::CallState::Held:
115       return headset::BTHF_CALL_STATE_HELD;
116     default:
117       log::fatal("Unhandled enum value from Rust");
118   }
119 }
120 
debug_dump_cb(bool active,uint16_t codec_id,int total_num_decoded_frames,double packet_loss_ratio,uint64_t begin_ts,uint64_t end_ts,const char * pkt_status_in_hex,const char * pkt_status_in_binary)121 static void debug_dump_cb(
122     bool active,
123     uint16_t codec_id,
124     int total_num_decoded_frames,
125     double packet_loss_ratio,
126     uint64_t begin_ts,
127     uint64_t end_ts,
128     const char* pkt_status_in_hex,
129     const char* pkt_status_in_binary) {
130   rusty::hfp_debug_dump_callback(
131       active,
132       codec_id,
133       total_num_decoded_frames,
134       packet_loss_ratio,
135       begin_ts,
136       end_ts,
137       ::rust::String{pkt_status_in_hex},
138       ::rust::String{pkt_status_in_binary});
139 }
140 }  // namespace internal
141 
142 class DBusHeadsetCallbacks : public headset::Callbacks {
143  public:
GetInstance(headset::Interface * headset)144   static Callbacks* GetInstance(headset::Interface* headset) {
145     static Callbacks* instance = new DBusHeadsetCallbacks(headset);
146     return instance;
147   }
148 
DBusHeadsetCallbacks(headset::Interface * headset)149   DBusHeadsetCallbacks(headset::Interface* headset) : headset_(headset){};
150 
151   // headset::Callbacks
ConnectionStateCallback(headset::bthf_connection_state_t state,RawAddress * bd_addr)152   void ConnectionStateCallback(headset::bthf_connection_state_t state, RawAddress* bd_addr) override {
153     log::info("ConnectionStateCallback from {}", *bd_addr);
154     topshim::rust::internal::connection_state_cb(state, bd_addr);
155   }
156 
AudioStateCallback(headset::bthf_audio_state_t state,RawAddress * bd_addr)157   void AudioStateCallback(headset::bthf_audio_state_t state, RawAddress* bd_addr) override {
158     log::info("AudioStateCallback {} from {}", state, *bd_addr);
159     topshim::rust::internal::audio_state_cb(state, bd_addr);
160   }
161 
VoiceRecognitionCallback(headset::bthf_vr_state_t state,RawAddress * bd_addr)162   void VoiceRecognitionCallback(
163       [[maybe_unused]] headset::bthf_vr_state_t state, [[maybe_unused]] RawAddress* bd_addr) override {}
164 
AnswerCallCallback(RawAddress * bd_addr)165   void AnswerCallCallback(RawAddress* bd_addr) override {
166     topshim::rust::internal::answer_call_cb(bd_addr);
167   }
168 
HangupCallCallback(RawAddress * bd_addr)169   void HangupCallCallback(RawAddress* bd_addr) override {
170     topshim::rust::internal::hangup_call_cb(bd_addr);
171   }
172 
VolumeControlCallback(headset::bthf_volume_type_t type,int volume,RawAddress * bd_addr)173   void VolumeControlCallback(headset::bthf_volume_type_t type, int volume, RawAddress* bd_addr) override {
174     if (volume < 0) return;
175     if (volume > 15) volume = 15;
176     if (type == headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK) {
177       log::info("VolumeControlCallback (Spk) {} from {}", volume, *bd_addr);
178       topshim::rust::internal::volume_update_cb(volume, bd_addr);
179     } else if (type == headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_MIC) {
180       log::info("VolumeControlCallback (Mic) {} from {}", volume, *bd_addr);
181       topshim::rust::internal::mic_volume_update_cb(volume, bd_addr);
182     }
183   }
184 
DialCallCallback(char * number,RawAddress * bd_addr)185   void DialCallCallback(char* number, RawAddress* bd_addr) override {
186     topshim::rust::internal::dial_call_cb(number, bd_addr);
187   }
188 
DtmfCmdCallback(char tone,RawAddress * bd_addr)189   void DtmfCmdCallback([[maybe_unused]] char tone, [[maybe_unused]] RawAddress* bd_addr) override {}
190 
NoiseReductionCallback(headset::bthf_nrec_t nrec,RawAddress * bd_addr)191   void NoiseReductionCallback(
192       [[maybe_unused]] headset::bthf_nrec_t nrec, [[maybe_unused]] RawAddress* bd_addr) override {}
193 
WbsCallback(headset::bthf_wbs_config_t wbs,RawAddress * addr)194   void WbsCallback(headset::bthf_wbs_config_t wbs, RawAddress* addr) override {
195     log::info("WbsCallback {} from {}", wbs, *addr);
196     rusty::hfp_wbs_caps_update_callback(wbs == headset::BTHF_WBS_YES, *addr);
197   }
198 
SwbCallback(headset::bthf_swb_codec_t codec,headset::bthf_swb_config_t swb,RawAddress * addr)199   void SwbCallback(
200       headset::bthf_swb_codec_t codec, headset::bthf_swb_config_t swb, RawAddress* addr) override {
201     log::info("SwbCallback codec:{}, swb:{} from {}", codec, swb, *addr);
202     rusty::hfp_swb_caps_update_callback(
203         (codec == headset::BTHF_SWB_CODEC_LC3 && swb == headset::BTHF_SWB_YES), *addr);
204   }
205 
AtChldCallback(headset::bthf_chld_type_t chld,RawAddress * bd_addr)206   void AtChldCallback(headset::bthf_chld_type_t chld, RawAddress* bd_addr) override {
207     topshim::rust::internal::call_hold_cb(chld, bd_addr);
208   }
209 
AtCnumCallback(RawAddress * bd_addr)210   void AtCnumCallback(RawAddress* bd_addr) override {
211     // Send an OK response to HF to indicate that we have no subscriber info.
212     // This is mandatory support for passing HFP/AG/NUM/BV-01-I.
213     headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
214   }
215 
AtCindCallback(RawAddress * bd_addr)216   void AtCindCallback(RawAddress* bd_addr) override {
217     topshim::rust::internal::indicator_query_cb(bd_addr);
218   }
219 
AtCopsCallback(RawAddress * bd_addr)220   void AtCopsCallback(RawAddress* bd_addr) override {
221     log::warn("Respond +COPS: 0 to AT+COPS? from {}", *bd_addr);
222     headset_->CopsResponse("", bd_addr);
223   }
224 
AtClccCallback(RawAddress * bd_addr)225   void AtClccCallback(RawAddress* bd_addr) override {
226     topshim::rust::internal::current_calls_query_cb(bd_addr);
227   }
228 
UnknownAtCallback(char * at_string,RawAddress * bd_addr)229   void UnknownAtCallback(char* at_string, RawAddress* bd_addr) override {
230     const std::string at_command = common::ToString(at_string);
231     // We are able to support +XAPL, +IPHONEACCEV, and +XEVENT commands,
232     // everything else will get an error reply.
233     const bool is_xapl = at_command.find("+XAPL") != std::string::npos;
234     const bool is_iphoneaccev = at_command.find("+IPHONEACCEV") != std::string::npos;
235     const bool is_xevent = at_command.find("+XEVENT") != std::string::npos;
236     if (!is_xapl && !is_iphoneaccev && !is_xevent) {
237       log::warn("Reply Error to UnknownAtCallback:{}", at_string);
238       headset_->AtResponse(headset::BTHF_AT_RESPONSE_ERROR, 0, bd_addr);
239       return;
240     }
241 
242     if (is_xapl) {
243       // Respond that we support battery level reporting only (2).
244       headset_->FormattedAtResponse("+XAPL=iPhone,2", bd_addr);
245     }
246 
247     // Ack all supported commands and bubble commands up for further processing
248     // if desired.
249     topshim::rust::internal::vendor_specific_at_command_cb(at_string, bd_addr);
250     headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
251   }
252 
KeyPressedCallback(RawAddress * bd_addr)253   void KeyPressedCallback([[maybe_unused]] RawAddress* bd_addr) override {}
254 
AtBindCallback(char * at_string,RawAddress * bd_addr)255   void AtBindCallback(char* at_string, RawAddress* bd_addr) override {
256     log::warn(
257         "AT+BIND {} from addr {}: Bluetooth HF Indicators is not supported.", at_string, *bd_addr);
258   }
259 
AtBievCallback(headset::bthf_hf_ind_type_t ind_id,int ind_value,RawAddress * bd_addr)260   void AtBievCallback(headset::bthf_hf_ind_type_t ind_id, int ind_value, RawAddress* bd_addr) override {
261     switch (ind_id) {
262       case headset::bthf_hf_ind_type_t::BTHF_HF_IND_ENHANCED_DRIVER_SAFETY:
263         // We don't do anything with this but we do know what it is, send OK.
264         headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
265         break;
266       case headset::bthf_hf_ind_type_t::BTHF_HF_IND_BATTERY_LEVEL_STATUS:
267         topshim::rust::internal::battery_level_update_cb(ind_value, bd_addr);
268         headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
269         break;
270       default:
271         log::warn("AT+BIEV indicator {} with value {} from addr {}", ind_id, ind_value, *bd_addr);
272         return;
273     }
274   }
275 
AtBiaCallback(bool service,bool roam,bool signal,bool battery,RawAddress * bd_addr)276   void AtBiaCallback(bool service, bool roam, bool signal, bool battery, RawAddress* bd_addr) override {
277     log::warn("AT+BIA=,,{},{},{},{},from addr {}", service, signal, roam, battery, *bd_addr);
278   }
279 
DebugDumpCallback(bool active,uint16_t codec_id,int total_num_decoded_frames,double packet_loss_ratio,uint64_t begin_ts,uint64_t end_ts,const char * pkt_status_in_hex,const char * pkt_status_in_binary)280   void DebugDumpCallback(
281       bool active,
282       uint16_t codec_id,
283       int total_num_decoded_frames,
284       double packet_loss_ratio,
285       uint64_t begin_ts,
286       uint64_t end_ts,
287       const char* pkt_status_in_hex,
288       const char* pkt_status_in_binary) override {
289     log::warn(
290         "DebugDumpCallback {} {} {} {:f} {} {} {} {}",
291         active,
292         codec_id,
293         total_num_decoded_frames,
294         packet_loss_ratio,
295         (unsigned long long)begin_ts,
296         (unsigned long long)end_ts,
297         pkt_status_in_hex,
298         pkt_status_in_binary);
299     topshim::rust::internal::debug_dump_cb(
300         active,
301         codec_id,
302         total_num_decoded_frames,
303         packet_loss_ratio,
304         begin_ts,
305         end_ts,
306         pkt_status_in_hex,
307         pkt_status_in_binary);
308   }
309 
310  private:
311   headset::Interface* headset_;
312 };
313 
init()314 int HfpIntf::init() {
315   return intf_->Init(DBusHeadsetCallbacks::GetInstance(intf_), 1, false);
316 }
317 
connect(RawAddress addr)318 uint32_t HfpIntf::connect(RawAddress addr) {
319   return intf_->Connect(&addr);
320 }
321 
connect_audio(RawAddress addr,bool sco_offload,int disabled_codecs)322 int HfpIntf::connect_audio(RawAddress addr, bool sco_offload, int disabled_codecs) {
323   intf_->SetScoOffloadEnabled(sco_offload);
324   return intf_->ConnectAudio(&addr, disabled_codecs);
325 }
326 
set_active_device(RawAddress addr)327 int HfpIntf::set_active_device(RawAddress addr) {
328   return intf_->SetActiveDevice(&addr);
329 }
330 
set_volume(int8_t volume,RawAddress addr)331 int HfpIntf::set_volume(int8_t volume, RawAddress addr) {
332   return intf_->VolumeControl(headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK, volume, &addr);
333 }
334 
set_mic_volume(int8_t volume,RawAddress addr)335 uint32_t HfpIntf::set_mic_volume(int8_t volume, RawAddress addr) {
336   return intf_->VolumeControl(headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_MIC, volume, &addr);
337 }
338 
disconnect(RawAddress addr)339 uint32_t HfpIntf::disconnect(RawAddress addr) {
340   return intf_->Disconnect(&addr);
341 }
342 
disconnect_audio(RawAddress addr)343 int HfpIntf::disconnect_audio(RawAddress addr) {
344   return intf_->DisconnectAudio(&addr);
345 }
346 
device_status_notification(TelephonyDeviceStatus status,RawAddress addr)347 uint32_t HfpIntf::device_status_notification(TelephonyDeviceStatus status, RawAddress addr) {
348   return intf_->DeviceStatusNotification(
349       status.network_available ? headset::BTHF_NETWORK_STATE_AVAILABLE
350                                : headset::BTHF_NETWORK_STATE_NOT_AVAILABLE,
351       status.roaming ? headset::BTHF_SERVICE_TYPE_ROAMING : headset::BTHF_SERVICE_TYPE_HOME,
352       status.signal_strength,
353       status.battery_level,
354       &addr);
355 }
356 
indicator_query_response(TelephonyDeviceStatus device_status,PhoneState phone_state,RawAddress addr)357 uint32_t HfpIntf::indicator_query_response(
358     TelephonyDeviceStatus device_status, PhoneState phone_state, RawAddress addr) {
359   return intf_->CindResponse(
360       device_status.network_available ? 1 : 0,
361       phone_state.num_active,
362       phone_state.num_held,
363       topshim::rust::internal::from_rust_call_state(phone_state.state),
364       device_status.signal_strength,
365       device_status.roaming ? 1 : 0,
366       device_status.battery_level,
367       &addr);
368 }
369 
current_calls_query_response(const::rust::Vec<CallInfo> & call_list,RawAddress addr)370 uint32_t HfpIntf::current_calls_query_response(
371     const ::rust::Vec<CallInfo>& call_list, RawAddress addr) {
372   for (const auto& c : call_list) {
373     std::string number{c.number};
374     intf_->ClccResponse(
375         c.index,
376         c.dir_incoming ? headset::BTHF_CALL_DIRECTION_INCOMING
377                        : headset::BTHF_CALL_DIRECTION_OUTGOING,
378         topshim::rust::internal::from_rust_call_state(c.state),
379         /*mode=*/headset::BTHF_CALL_TYPE_VOICE,
380         /*multi_party=*/headset::BTHF_CALL_MPTY_TYPE_SINGLE,
381         number.c_str(),
382         /*type=*/headset::BTHF_CALL_ADDRTYPE_UNKNOWN,
383         &addr);
384   }
385 
386   // NULL termination (Completes response)
387   return intf_->ClccResponse(
388       /*index=*/0,
389       /*dir=*/(headset::bthf_call_direction_t)0,
390       /*state=*/(headset::bthf_call_state_t)0,
391       /*mode=*/(headset::bthf_call_mode_t)0,
392       /*multi_party=*/(headset::bthf_call_mpty_type_t)0,
393       /*number=*/"",
394       /*type=*/(headset::bthf_call_addrtype_t)0,
395       &addr);
396 }
397 
phone_state_change(PhoneState phone_state,const::rust::String & number_rs,RawAddress addr)398 uint32_t HfpIntf::phone_state_change(
399     PhoneState phone_state, const ::rust::String& number_rs, RawAddress addr) {
400   std::string number{number_rs};
401   return intf_->PhoneStateChange(
402       phone_state.num_active,
403       phone_state.num_held,
404       topshim::rust::internal::from_rust_call_state(phone_state.state),
405       number.c_str(),
406       /*type=*/(headset::bthf_call_addrtype_t)0,
407       /*name=*/"",
408       &addr);
409 }
410 
simple_at_response(bool ok,RawAddress addr)411 uint32_t HfpIntf::simple_at_response(bool ok, RawAddress addr) {
412   return intf_->AtResponse(
413       (ok ? headset::BTHF_AT_RESPONSE_OK : headset::BTHF_AT_RESPONSE_ERROR), 0, &addr);
414 }
415 
debug_dump()416 void HfpIntf::debug_dump() {
417   intf_->DebugDump();
418 }
419 
cleanup()420 void HfpIntf::cleanup() {}
421 
GetHfpProfile(const unsigned char * btif)422 std::unique_ptr<HfpIntf> GetHfpProfile(const unsigned char* btif) {
423   if (internal::g_hfpif) std::abort();
424 
425   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
426 
427   auto hfpif = std::make_unique<HfpIntf>(const_cast<headset::Interface*>(
428       reinterpret_cast<const headset::Interface*>(btif_->get_profile_interface("handsfree"))));
429   internal::g_hfpif = hfpif.get();
430 
431   return hfpif;
432 }
433 
interop_insert_call_when_sco_start(RawAddress addr)434 bool interop_insert_call_when_sco_start(RawAddress addr) {
435   return interop_match_addr(interop_feature_t::INTEROP_INSERT_CALL_WHEN_SCO_START, &addr);
436 }
437 
438 }  // namespace rust
439 }  // namespace topshim
440 }  // namespace bluetooth
441