• 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 "gd/rust/topshim/common/utils.h"
22 #include "include/hardware/bt_hf.h"
23 #include "src/profiles/hfp.rs.h"
24 #include "types/raw_address.h"
25 
26 namespace rusty = ::bluetooth::topshim::rust;
27 
28 namespace bluetooth {
29 namespace topshim {
30 namespace rust {
31 namespace internal {
32 static HfpIntf* g_hfpif;
33 
connection_state_cb(bluetooth::headset::bthf_connection_state_t state,RawAddress * addr)34 static void connection_state_cb(bluetooth::headset::bthf_connection_state_t state, RawAddress* addr) {
35   RustRawAddress raddr = rusty::CopyToRustAddress(*addr);
36   rusty::hfp_connection_state_callback(state, raddr);
37 }
38 
audio_state_cb(bluetooth::headset::bthf_audio_state_t state,RawAddress * addr)39 static void audio_state_cb(bluetooth::headset::bthf_audio_state_t state, RawAddress* addr) {
40   RustRawAddress raddr = rusty::CopyToRustAddress(*addr);
41   rusty::hfp_audio_state_callback(state, raddr);
42 }
43 
44 }  // namespace internal
45 
46 class DBusHeadsetCallbacks : public headset::Callbacks {
47  public:
GetInstance(headset::Interface * headset)48   static Callbacks* GetInstance(headset::Interface* headset) {
49     static Callbacks* instance = new DBusHeadsetCallbacks(headset);
50     return instance;
51   }
52 
DBusHeadsetCallbacks(headset::Interface * headset)53   DBusHeadsetCallbacks(headset::Interface* headset) : headset_(headset) {
54     call_status = 0;
55   };
56 
57   // headset::Callbacks
ConnectionStateCallback(headset::bthf_connection_state_t state,RawAddress * bd_addr)58   void ConnectionStateCallback(headset::bthf_connection_state_t state, RawAddress* bd_addr) override {
59     LOG_INFO("ConnectionStateCallback from %s", bd_addr->ToString().c_str());
60     topshim::rust::internal::connection_state_cb(state, bd_addr);
61   }
62 
AudioStateCallback(headset::bthf_audio_state_t state,RawAddress * bd_addr)63   void AudioStateCallback(headset::bthf_audio_state_t state, RawAddress* bd_addr) override {
64     LOG_INFO("AudioStateCallback %u from %s", state, bd_addr->ToString().c_str());
65     topshim::rust::internal::audio_state_cb(state, bd_addr);
66 
67     switch (state) {
68       case headset::bthf_audio_state_t::BTHF_AUDIO_STATE_CONNECTED:
69         SetCallStatus(1, bd_addr);
70         // This triggers a +VGS command to set the speaker volume for HFP
71         // devices.
72         // TODO(b/215089433): Add a set volume API and have client to handle the
73         // set volume when start.
74         headset_->VolumeControl(headset::bthf_volume_type_t::BTHF_VOLUME_TYPE_SPK, 5, bd_addr);
75         return;
76       case headset::bthf_audio_state_t::BTHF_AUDIO_STATE_DISCONNECTED:
77         SetCallStatus(0, bd_addr);
78         return;
79       default:
80         return;
81     }
82   }
83 
VoiceRecognitionCallback(headset::bthf_vr_state_t state,RawAddress * bd_addr)84   void VoiceRecognitionCallback(
85       [[maybe_unused]] headset::bthf_vr_state_t state, [[maybe_unused]] RawAddress* bd_addr) override {}
86 
AnswerCallCallback(RawAddress * bd_addr)87   void AnswerCallCallback([[maybe_unused]] RawAddress* bd_addr) override {}
88 
HangupCallCallback(RawAddress * bd_addr)89   void HangupCallCallback([[maybe_unused]] RawAddress* bd_addr) override {}
90 
VolumeControlCallback(headset::bthf_volume_type_t type,int volume,RawAddress * bd_addr)91   void VolumeControlCallback(
92       [[maybe_unused]] headset::bthf_volume_type_t type,
93       [[maybe_unused]] int volume,
94       [[maybe_unused]] RawAddress* bd_addr) override {}
95 
DialCallCallback(char * number,RawAddress * bd_addr)96   void DialCallCallback([[maybe_unused]] char* number, [[maybe_unused]] RawAddress* bd_addr) override {}
97 
DtmfCmdCallback(char tone,RawAddress * bd_addr)98   void DtmfCmdCallback([[maybe_unused]] char tone, [[maybe_unused]] RawAddress* bd_addr) override {}
99 
NoiseReductionCallback(headset::bthf_nrec_t nrec,RawAddress * bd_addr)100   void NoiseReductionCallback(
101       [[maybe_unused]] headset::bthf_nrec_t nrec, [[maybe_unused]] RawAddress* bd_addr) override {}
102 
WbsCallback(headset::bthf_wbs_config_t wbs,RawAddress * bd_addr)103   void WbsCallback([[maybe_unused]] headset::bthf_wbs_config_t wbs, [[maybe_unused]] RawAddress* bd_addr) override {}
104 
AtChldCallback(headset::bthf_chld_type_t chld,RawAddress * bd_addr)105   void AtChldCallback([[maybe_unused]] headset::bthf_chld_type_t chld, [[maybe_unused]] RawAddress* bd_addr) override {}
106 
AtCnumCallback(RawAddress * bd_addr)107   void AtCnumCallback([[maybe_unused]] RawAddress* bd_addr) override {}
108 
AtCindCallback(RawAddress * bd_addr)109   void AtCindCallback(RawAddress* bd_addr) override {
110     // This is required to setup the SLC, the format of the response should be
111     // +CIND: <call>,<callsetup>,<service>,<signal>,<roam>,<battery>,<callheld>
112     LOG_WARN("Respond +CIND: 0,0,1,5,0,5,0 to AT+CIND? from %s", bd_addr->ToString().c_str());
113 
114     // headset::Interface::CindResponse's parameters are similar but different
115     // from the actual CIND response. It will construct the final response for
116     // you based on the arguments you provide.
117     // CindResponse(network_service_availability, active_call_num,
118     //              held_call_num, callsetup_state, signal_strength,
119     //              roam_state, battery_level, bd_addr);
120     headset_->CindResponse(1, 0, 0, headset::BTHF_CALL_STATE_IDLE, 5, 0, 5, bd_addr);
121   }
122 
AtCopsCallback(RawAddress * bd_addr)123   void AtCopsCallback(RawAddress* bd_addr) override {
124     LOG_WARN("Respond +COPS: 0 to AT+COPS? from %s", bd_addr->ToString().c_str());
125     headset_->CopsResponse("", bd_addr);
126   }
127 
AtClccCallback(RawAddress * bd_addr)128   void AtClccCallback(RawAddress* bd_addr) override {
129     // Reply +CLCC:<idx>,<dir>,<status>,<mode>,<mprty>[,<number>,<type>] if
130     // there is an active audio connection. Simply rely OK otherwise.
131     // This is required for some headsets to start to send actual data to AG.
132     if (call_status)
133       headset_->ClccResponse(
134           /*index=*/1,
135           /*dir=*/headset::BTHF_CALL_DIRECTION_OUTGOING,
136           /*state=*/headset::BTHF_CALL_STATE_ACTIVE,
137           /*mode=*/headset::BTHF_CALL_TYPE_VOICE,
138           /*multi_party=*/headset::BTHF_CALL_MPTY_TYPE_SINGLE,
139           /*number=*/"",
140           /*type=*/headset::BTHF_CALL_ADDRTYPE_UNKNOWN,
141           bd_addr);
142 
143     headset_->AtResponse(headset::BTHF_AT_RESPONSE_OK, 0, bd_addr);
144   }
145 
UnknownAtCallback(char * at_string,RawAddress * bd_addr)146   void UnknownAtCallback(char* at_string, RawAddress* bd_addr) override {
147     LOG_WARN("Reply Error to UnknownAtCallback:%s", at_string);
148     headset_->AtResponse(headset::BTHF_AT_RESPONSE_ERROR, 0, bd_addr);
149   }
150 
KeyPressedCallback(RawAddress * bd_addr)151   void KeyPressedCallback([[maybe_unused]] RawAddress* bd_addr) override {}
152 
AtBindCallback(char * at_string,RawAddress * bd_addr)153   void AtBindCallback(char* at_string, RawAddress* bd_addr) override {
154     LOG_WARN(
155         "AT+BIND %s from addr %s: Bluetooth HF Indicators is not supported.", at_string, bd_addr->ToString().c_str());
156   }
157 
AtBievCallback(headset::bthf_hf_ind_type_t ind_id,int ind_value,RawAddress * bd_addr)158   void AtBievCallback(headset::bthf_hf_ind_type_t ind_id, int ind_value, RawAddress* bd_addr) override {
159     LOG_WARN(
160         "AT+BIEV=%d,%d from addr %s: Bluetooth HF Indicators is not supported.",
161         ind_id,
162         ind_value,
163         bd_addr->ToString().c_str());
164   }
165 
AtBiaCallback(bool service,bool roam,bool signal,bool battery,RawAddress * bd_addr)166   void AtBiaCallback(bool service, bool roam, bool signal, bool battery, RawAddress* bd_addr) override {
167     LOG_WARN("AT+BIA=,,%d,%d,%d,%d,from addr %s", service, signal, roam, battery, bd_addr->ToString().c_str());
168   }
169 
170  private:
171   headset::Interface* headset_;
172   int call_status;
173 
SetCallStatus(int call,RawAddress * bd_addr)174   void SetCallStatus(int call, RawAddress* bd_addr) {
175     if (call == call_status) return;
176 
177     if (call) {
178       // This triggers a +CIEV command to set the call status for HFP
179       // devices. It is required along with the SCO establishment for some
180       // devices to provide sound.
181       headset_->PhoneStateChange(
182           /*num_active=*/1,
183           /*num_held=*/0,
184           /*call_setup_state=*/headset::bthf_call_state_t::BTHF_CALL_STATE_IDLE,
185           /*number=*/"",
186           /*type=*/(headset::bthf_call_addrtype_t)0,
187           /*name=*/"",
188           /*bd_addr=*/bd_addr);
189     } else {
190       headset_->PhoneStateChange(
191           /*num_active=*/0,
192           /*num_held=*/0,
193           /*call_setup_state=*/headset::bthf_call_state_t::BTHF_CALL_STATE_IDLE,
194           /*number=*/"",
195           /*type=*/(headset::bthf_call_addrtype_t)0,
196           /*name=*/"",
197           /*bd_addr=*/bd_addr);
198     }
199 
200     call_status = call;
201   }
202 };
203 
init()204 int HfpIntf::init() {
205   return intf_->Init(DBusHeadsetCallbacks::GetInstance(intf_), 1, false);
206 }
207 
connect(RustRawAddress bt_addr)208 int HfpIntf::connect(RustRawAddress bt_addr) {
209   RawAddress addr = rusty::CopyFromRustAddress(bt_addr);
210   return intf_->Connect(&addr);
211 }
212 
connect_audio(RustRawAddress bt_addr)213 int HfpIntf::connect_audio(RustRawAddress bt_addr) {
214   RawAddress addr = rusty::CopyFromRustAddress(bt_addr);
215   return intf_->ConnectAudio(&addr);
216 }
217 
disconnect(RustRawAddress bt_addr)218 int HfpIntf::disconnect(RustRawAddress bt_addr) {
219   RawAddress addr = rusty::CopyFromRustAddress(bt_addr);
220   return intf_->Disconnect(&addr);
221 }
222 
disconnect_audio(RustRawAddress bt_addr)223 int HfpIntf::disconnect_audio(RustRawAddress bt_addr) {
224   RawAddress addr = rusty::CopyFromRustAddress(bt_addr);
225   return intf_->DisconnectAudio(&addr);
226 }
227 
cleanup()228 void HfpIntf::cleanup() {}
229 
GetHfpProfile(const unsigned char * btif)230 std::unique_ptr<HfpIntf> GetHfpProfile(const unsigned char* btif) {
231   if (internal::g_hfpif) std::abort();
232 
233   const bt_interface_t* btif_ = reinterpret_cast<const bt_interface_t*>(btif);
234 
235   auto hfpif = std::make_unique<HfpIntf>(const_cast<headset::Interface*>(
236       reinterpret_cast<const headset::Interface*>(btif_->get_profile_interface("handsfree"))));
237   internal::g_hfpif = hfpif.get();
238 
239   return hfpif;
240 }
241 
242 }  // namespace rust
243 }  // namespace topshim
244 }  // namespace bluetooth
245