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