• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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