1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hfp_hf_audio_connection.h"
17 
18 #include "btstack.h"
19 #include "hfp_hf_profile_event_sender.h"
20 #include "log_util.h"
21 #include "raw_address.h"
22 #include "securec.h"
23 
24 namespace OHOS {
25 namespace bluetooth {
26 std::vector<HfpHfAudioConnection::AudioDevice> HfpHfAudioConnection::g_audioDevices;
27 
28 BtmScoCallbacks HfpHfAudioConnection::g_cbs = {
29     &HfpHfAudioConnection::OnConnectCompleted,
30     &HfpHfAudioConnection::OnConnectionChanged,
31     &HfpHfAudioConnection::OnDisconnectCompleted,
32     &HfpHfAudioConnection::OnConnectRequest,
33     &HfpHfAudioConnection::OnWriteVoiceSettingCompleted,
34 };
35 
SetRemoteAddr(const std::string & addr)36 void HfpHfAudioConnection::SetRemoteAddr(const std::string &addr)
37 {
38     remoteAddr_ = addr;
39 }
40 
ConvertToBtAddr(const std::string & address)41 BtAddr HfpHfAudioConnection::ConvertToBtAddr(const std::string &address)
42 {
43     RawAddress rawAddr(address);
44     BtAddr btAddr;
45     rawAddr.ConvertToUint8(btAddr.addr);
46     btAddr.type = BT_PUBLIC_DEVICE_ADDRESS;
47     return btAddr;
48 }
49 
Register()50 int HfpHfAudioConnection::Register()
51 {
52     HILOGI("[HFP HF] Audio Register start");
53     std::vector<HfpHfAudioConnection::AudioDevice>().swap(g_audioDevices);
54     int ret = BTM_RegisterScoCallbacks(&g_cbs, nullptr);
55     HFP_HF_RETURN_IF_FAIL(ret);
56     return ret;
57 }
58 
Deregister()59 int HfpHfAudioConnection::Deregister()
60 {
61     HILOGI("[HFP HF] Audio Deregister start");
62     std::vector<HfpHfAudioConnection::AudioDevice>().swap(g_audioDevices);
63     int ret = BTM_DeregisterScoCallbacks(&g_cbs);
64     HFP_HF_RETURN_IF_FAIL(ret);
65     return ret;
66 }
67 
IsAudioConnected()68 bool HfpHfAudioConnection::IsAudioConnected()
69 {
70     std::vector<HfpHfAudioConnection::AudioDevice>::iterator it;
71     for (it = g_audioDevices.begin(); it != g_audioDevices.end(); ++it) {
72         if (it->lastConnectResult == CONNECT_SUCCESS) {
73             return true;
74         }
75     }
76     return false;
77 }
78 
SetSupportFeatures(bool escoSupport,bool escoS4Support,int inUseCodec)79 void HfpHfAudioConnection::SetSupportFeatures(bool escoSupport, bool escoS4Support, int inUseCodec)
80 {
81     escoSupport_ = escoSupport;
82     escoS4Support_ = escoS4Support;
83     inUseCodec_ = inUseCodec;
84     HILOGI("[HFP HF] escoSupport_[%{public}d], escoS4Support_[%{public}d], inUseCodec_[%{public}d]",
85         escoSupport_, escoS4Support_, inUseCodec_);
86 }
87 
GetDeviceByAddr(const std::string & addr)88 std::vector<HfpHfAudioConnection::AudioDevice>::iterator HfpHfAudioConnection::GetDeviceByAddr(const std::string &addr)
89 {
90     std::vector<HfpHfAudioConnection::AudioDevice>::iterator it;
91     for (it = g_audioDevices.begin(); it != g_audioDevices.end(); ++it) {
92         if (it->addr == addr) {
93             break;
94         }
95     }
96     return it;
97 }
98 
GetDeviceByHandle(uint16_t handle)99 std::vector<HfpHfAudioConnection::AudioDevice>::iterator HfpHfAudioConnection::GetDeviceByHandle(uint16_t handle)
100 {
101     std::vector<HfpHfAudioConnection::AudioDevice>::iterator it;
102     for (it = g_audioDevices.begin(); it != g_audioDevices.end(); ++it) {
103         if (it->handle == handle) {
104             break;
105         }
106     }
107     return it;
108 }
109 
ConnectByCvsd(AudioDevice & dev,BtAddr btAddr,bool cvsdEscoFailed) const110 int HfpHfAudioConnection::ConnectByCvsd(AudioDevice &dev, BtAddr btAddr, bool cvsdEscoFailed) const
111 {
112     int ret = BTM_WriteVoiceSetting(BTM_VOICE_SETTING_CVSD);
113     HFP_HF_RETURN_IF_FAIL(ret);
114 
115     if (escoSupport_ && !cvsdEscoFailed) {
116         dev.linkType = LINK_TYPE_ESCO;
117         if (escoS4Support_) {
118             HILOGI("[HFP HF] Try connect by CVSD ESCO S4.");
119             dev.lastParam = CVSD_ESCO_S4;
120             BtmCreateEscoConnectionParam param = CVSD_ESCO_S4_PARAM;
121             param.addr = btAddr;
122             ret = BTM_CreateEscoConnection(&param);
123             HFP_HF_RETURN_IF_FAIL(ret);
124         } else {
125             HILOGI("[HFP HF] Try connect by CVSD ESCO S1.");
126             dev.lastParam = CVSD_ESCO_S1;
127             BtmCreateEscoConnectionParam param = CVSD_ESCO_S1_PARAM;
128             param.addr = btAddr;
129             ret = BTM_CreateEscoConnection(&param);
130             HFP_HF_RETURN_IF_FAIL(ret);
131         }
132     } else {
133         if (!BTM_IsSecureConnection(&btAddr)) {
134             dev.linkType = LINK_TYPE_SCO;
135             HILOGI("[HFP HF] Try connect by CVSD SCO.");
136             dev.lastParam = CVSD_SCO;
137             BtmCreateScoConnectionParam param = CVSD_SCO_PARAM;
138             param.addr = btAddr;
139             ret = BTM_CreateScoConnection(&param);
140             HFP_HF_RETURN_IF_FAIL(ret);
141         } else {
142             HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(remoteAddr_, HFP_HF_AUDIO_CONNECT_FAILED_EVT);
143             return ret;
144         }
145     }
146 
147     HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(remoteAddr_, HFP_HF_AUDIO_CONNECTING_EVT);
148     return ret;
149 }
150 
ConnectAudio() const151 int HfpHfAudioConnection::ConnectAudio() const
152 {
153     HILOGI("[HFP HF] Connect SCO to %{public}s", GetEncryptAddr(remoteAddr_).c_str());
154 
155     auto dev = GetDeviceByAddr(remoteAddr_);
156     if (dev == g_audioDevices.end()) {
157         HfpHfAudioConnection::AudioDevice audioDev;
158         audioDev.role = ROLE_INITIATOR;
159         audioDev.addr = remoteAddr_;
160         g_audioDevices.push_back(audioDev);
161         dev = GetDeviceByAddr(remoteAddr_);
162         HILOGI("[HFP HF] Create Audio device for [%{public}s]", GetEncryptAddr(remoteAddr_).c_str());
163     } else {
164         HILOGI("[HFP HF] Audio device [%{public}s] already in device list ", GetEncryptAddr(remoteAddr_).c_str());
165     }
166 
167     bool cvsdEscoFailed = false;
168     if (dev->lastConnectResult == CONNECT_FAIL) {
169         if (dev->lastParam == CVSD_ESCO_S4 || dev->lastParam == CVSD_ESCO_S1) {
170             cvsdEscoFailed = true;
171         } else {
172             LOG_INFO("[HFP HF] Audio device [%{public}s], lastParam[%{public}d]",
173                 GetEncryptAddr(remoteAddr_).c_str(), dev->lastParam);
174         }
175     }
176 
177     BtAddr btAddr = ConvertToBtAddr(remoteAddr_);
178     return ConnectByCvsd(*dev, btAddr, cvsdEscoFailed);
179 }
180 
DisconnectAudio() const181 int HfpHfAudioConnection::DisconnectAudio() const
182 {
183     HILOGI("[HFP HF] Disconnect SCO from %{public}s", GetEncryptAddr(remoteAddr_).c_str());
184 
185     int ret;
186     auto dev = GetDeviceByAddr(remoteAddr_);
187     if (dev != g_audioDevices.end()) {
188         ret = BTM_DisconnectScoConnection(dev->handle, REMOTE_USER_TERMINATED_CONNECTION);
189         HFP_HF_RETURN_IF_FAIL(ret);
190         HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(remoteAddr_, HFP_HF_AUDIO_DISCONNECTING_EVT);
191     } else {
192         HILOGE("[HFP HF] Invalid Address remoteAddr_ %{public}s", GetEncryptAddr(remoteAddr_).c_str());
193         ret = BT_DEVICE_ERROR;
194     }
195     return ret;
196 }
197 
AcceptByMsbc(BtAddr btAddr)198 int HfpHfAudioConnection::AcceptByMsbc(BtAddr btAddr)
199 {
200     int ret = BTM_WriteVoiceSetting(BTM_VOICE_SETTING_TRANS);
201     HFP_HF_RETURN_IF_FAIL(ret);
202 
203     if (BTM_IsSecureConnection(&btAddr)) {
204         HILOGI("[HFP HF] Accept by MSBC T2.");
205         BtmCreateEscoConnectionParam param = MSBC_T2_PARAM;
206         param.addr = btAddr;
207         ret = BTM_AcceptEscoConnectionRequest(&param);
208         HFP_HF_RETURN_IF_FAIL(ret);
209     } else {
210         HILOGI("[HFP HF] Accept by MSBC T1.");
211         BtmCreateEscoConnectionParam param = MSBC_T1_PARAM;
212         param.addr = btAddr;
213         ret = BTM_AcceptEscoConnectionRequest(&param);
214         HFP_HF_RETURN_IF_FAIL(ret);
215     }
216     return ret;
217 }
218 
AcceptByCvsd(AudioDevice & dev,BtAddr btAddr) const219 int HfpHfAudioConnection::AcceptByCvsd(AudioDevice &dev, BtAddr btAddr) const
220 {
221     int ret = BTM_WriteVoiceSetting(BTM_VOICE_SETTING_CVSD);
222     HFP_HF_RETURN_IF_FAIL(ret);
223 
224     if (dev.linkType == LINK_TYPE_ESCO && escoSupport_) {
225         if (escoS4Support_) {
226             HILOGI("[HFP HF] Accept by CVSD ESCO S4.");
227             BtmCreateEscoConnectionParam param = CVSD_ESCO_S4_PARAM;
228             param.addr = btAddr;
229             ret = BTM_AcceptEscoConnectionRequest(&param);
230             HFP_HF_RETURN_IF_FAIL(ret);
231         } else {
232             HILOGI("[HFP HF] Accept by CVSD ESCO S1.");
233             BtmCreateEscoConnectionParam param = CVSD_ESCO_S1_PARAM;
234             param.addr = btAddr;
235             ret = BTM_AcceptEscoConnectionRequest(&param);
236             HFP_HF_RETURN_IF_FAIL(ret);
237         }
238     } else if (dev.linkType == LINK_TYPE_SCO) {
239         HILOGI("[HFP HF] Accept by CVSD SCO.");
240         BtmCreateScoConnectionParam param = CVSD_SCO_PARAM;
241         param.addr = btAddr;
242         ret = BTM_AcceptScoConnectionRequest(&param);
243         HFP_HF_RETURN_IF_FAIL(ret);
244     } else {
245         HILOGE("[HFP HF] Can not cvsd e(sco) connection, "
246             "because linktype[%{public}d] and escoSupport[%{public}d] are not matched!", dev.linkType, escoSupport_);
247         return BT_BAD_PARAM;
248     }
249     return ret;
250 }
251 
AcceptAudioConnection() const252 int HfpHfAudioConnection::AcceptAudioConnection() const
253 {
254     int ret = BT_SUCCESS;
255     BtAddr btAddr = ConvertToBtAddr(remoteAddr_);
256 
257     // Only accpet CVSD sco from remote device.
258     auto dev = GetDeviceByAddr(remoteAddr_);
259     if (dev != g_audioDevices.end()) {
260         if (inUseCodec_ == HFP_HF_CODEC_MSBC) {
261             if (dev->linkType == LINK_TYPE_ESCO && escoSupport_) {
262                 return AcceptByMsbc(btAddr);
263             } else {
264                 HILOGI("[HFP HF] Accpet MSBC ESCO connection failed, "
265                     "linktype[%{public}hhu] and escoSupport[%{public}d] are not matched", dev->linkType, escoSupport_);
266                 return BT_BAD_PARAM;
267             }
268         } else if (inUseCodec_ == HFP_HF_CODEC_CVSD) {
269             return AcceptByCvsd(*dev, btAddr);
270         } else {
271             HILOGI("[HFP HF] Invalid Codec[%{public}d]!", inUseCodec_);
272             return BT_BAD_PARAM;
273         }
274     } else {
275         HILOGE("[HFP HF] %{public}s:Invalid Address", GetEncryptAddr(remoteAddr_).c_str());
276         return BT_BAD_PARAM;
277     }
278 
279     return ret;
280 }
281 
RejectAudioConnection() const282 int HfpHfAudioConnection::RejectAudioConnection() const
283 {
284     HILOGI("[HFP HF] Reject sco connect request from %{public}s", GetEncryptAddr(remoteAddr_).c_str());
285     BtAddr btAddr = ConvertToBtAddr(remoteAddr_);
286     BtmRejectScoConnectionRequestParam param = {btAddr, REJECT_DUE_TO_LIMITED_RESOURCES};
287 
288     int ret = BTM_RejectScoConnectionRequest(&param);
289     HFP_HF_RETURN_IF_FAIL(ret);
290 
291     return ret;
292 }
293 
OnConnectRequest(const BtmScoConnectionRequestParam * param,void * context)294 void HfpHfAudioConnection::OnConnectRequest(const BtmScoConnectionRequestParam *param, void *context)
295 {
296     HILOGI("[HFP HF] enter");
297     HfpScoConnectionRequestParam parameters;
298     parameters.linkType = param->linkType;
299     (void)memcpy_s(&parameters.addr, sizeof(BtAddr), param->addr, sizeof(BtAddr));
300     HfpHfProfileEventSender::GetInstance().GetDispatchter()->PostTask(
301         std::bind(&HfpHfAudioConnection::ProcessOnConnectRequest, parameters));
302 }
303 
ProcessOnConnectRequest(HfpScoConnectionRequestParam parameters)304 void HfpHfAudioConnection::ProcessOnConnectRequest(HfpScoConnectionRequestParam parameters)
305 {
306     HILOGI("[HFP HF] enter");
307 
308     RawAddress btAddr = RawAddress::ConvertToString(parameters.addr.addr);
309     std::string address = btAddr.GetAddress();
310     auto dev = GetDeviceByAddr(address);
311     if (dev == g_audioDevices.end()) {
312         HfpHfAudioConnection::AudioDevice audioDev;
313         audioDev.role = ROLE_ACCEPTOR;
314         audioDev.addr = address;
315         audioDev.linkType = parameters.linkType;
316         g_audioDevices.push_back(audioDev);
317         HILOGI("[HFP HF] Create Audio device for [%{public}s]", GetEncryptAddr(address).c_str());
318     } else {
319         dev->linkType = parameters.linkType;
320         HILOGI("[HFP HF] Audio device [%{public}s] already in device list", GetEncryptAddr(address).c_str());
321     }
322     HfpHfProfileEventSender::GetInstance().ScoConnectRequest(
323         btAddr.GetAddress(), HFP_HF_AUDIO_CONNECT_REQUEST_EVT, parameters.linkType);
324 }
325 
OnConnectCompleted(const BtmScoConnectionCompleteParam * param,void * context)326 void HfpHfAudioConnection::OnConnectCompleted(const BtmScoConnectionCompleteParam *param, void *context)
327 {
328     HILOGI("[HFP HF] enter");
329     HfpScoConnectionCompleteParam parameters;
330     parameters.status = param->status;
331     parameters.connectionHandle = param->connectionHandle;
332     (void)memcpy_s(&parameters.addr, sizeof(BtAddr), param->addr, sizeof(BtAddr));
333     HfpHfProfileEventSender::GetInstance().GetDispatchter()->PostTask(
334         std::bind(&HfpHfAudioConnection::ProcessOnConnectCompleted, parameters));
335 }
336 
ProcessOnConnectCompleted(HfpScoConnectionCompleteParam parameters)337 void HfpHfAudioConnection::ProcessOnConnectCompleted(HfpScoConnectionCompleteParam parameters)
338 {
339     HILOGI("[HFP HF] enter");
340 
341     RawAddress btAddr = RawAddress::ConvertToString(parameters.addr.addr);
342     std::string address = btAddr.GetAddress();
343     auto dev = GetDeviceByAddr(address);
344     if (dev != g_audioDevices.end()) {
345         dev->addr = address;
346         dev->handle = parameters.connectionHandle;
347         if (!parameters.status) {
348             HILOGI("[HFP HF] SCO connect successfully!");
349             dev->lastConnectResult = CONNECT_SUCCESS;
350             HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(dev->addr, HFP_HF_AUDIO_CONNECTED_EVT);
351         } else {
352             ProcessOnConnectCompletedFail(dev, address);
353         }
354     } else {
355         HILOGI("[HFP HF] %{public}s: Invalid audio device", GetEncryptAddr(address).c_str());
356     }
357 }
358 
ProcessOnConnectCompletedFail(std::vector<HfpHfAudioConnection::AudioDevice>::iterator dev,const std::string & address)359 void HfpHfAudioConnection::ProcessOnConnectCompletedFail(
360     std::vector<HfpHfAudioConnection::AudioDevice>::iterator dev, const std::string &address)
361 {
362     dev->lastConnectResult = CONNECT_FAIL;
363     if (dev->role == ROLE_INITIATOR) {
364         if (dev->lastParam == CVSD_ESCO_S4 || dev->lastParam == CVSD_ESCO_S1) {
365             HILOGI("[HFP HF] CVSD ESCO failed, try CVSD SCO");
366             HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(dev->addr, HFP_HF_RETRY_CONNECT_AUDIO_EVT);
367         } else if (dev->lastParam == CVSD_SCO) {
368             HILOGI("[HFP HF] CVSD SCO failed, report fail event to service");
369             HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(dev->addr, HFP_HF_AUDIO_CONNECT_FAILED_EVT);
370         } else {
371             HILOGI("[HFP HF] address[%{public}s] lastParam[%{public}d] is invalid",
372                 GetEncryptAddr(address).c_str(), dev->lastParam);
373         }
374     } else {
375         // As acceptor, report connect failed event to service directly.
376         HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(dev->addr, HFP_HF_AUDIO_CONNECT_FAILED_EVT);
377         HILOGI("[HFP HF] Accept SCO from address[%{public}s]failed", GetEncryptAddr(address).c_str());
378     }
379 }
380 
OnDisconnectCompleted(const BtmScoDisconnectionCompleteParam * param,void * context)381 void HfpHfAudioConnection::OnDisconnectCompleted(const BtmScoDisconnectionCompleteParam *param, void *context)
382 {
383     HILOGI("[HFP HF] enter");
384     HfpScoDisconnectionCompleteParam parameters;
385     parameters.connectionHandle = param->connectionHandle;
386     parameters.reason = param->reason;
387     parameters.status = param->status;
388     HfpHfProfileEventSender::GetInstance().GetDispatchter()->PostTask(
389         std::bind(&HfpHfAudioConnection::ProcessOnDisconnectCompleted, parameters));
390 }
391 
ProcessOnDisconnectCompleted(HfpScoDisconnectionCompleteParam parameters)392 void HfpHfAudioConnection::ProcessOnDisconnectCompleted(HfpScoDisconnectionCompleteParam parameters)
393 {
394     HILOGI("[HFP HF] enter");
395 
396     auto it = GetDeviceByHandle(parameters.connectionHandle);
397     if (it != g_audioDevices.end()) {
398         if (!parameters.status) {
399             HILOGI("Disconnect SCO from address: %{public}s successfully.", GetEncryptAddr(it->addr).c_str());
400             HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(it->addr, HFP_HF_AUDIO_DISCONNECTED_EVT);
401             g_audioDevices.erase(it);
402         } else {
403             HILOGI("Disconnect SCO from address: %{public}s failed.", GetEncryptAddr(it->addr).c_str());
404             HfpHfProfileEventSender::GetInstance().UpdateScoConnectState(
405                 it->addr, HFP_HF_AUDIO_DISCONNECT_FAILED_EVT);
406         }
407     } else {
408         HILOGE("[HFP HF] Invalid audio device");
409     }
410 }
411 
OnConnectionChanged(const BtmScoConnectionChangedParam * param,void * context)412 void HfpHfAudioConnection::OnConnectionChanged(const BtmScoConnectionChangedParam *param, void *context)
413 {
414     HILOGI("[HFP HF] connectionHandle[%{public}hu]", param->connectionHandle);
415 }
416 
OnWriteVoiceSettingCompleted(uint8_t status,void * context)417 void HfpHfAudioConnection::OnWriteVoiceSettingCompleted(uint8_t status, void *context)
418 {
419     HILOGI("[HFP HF] status[%{public}hhu]", status);
420 }
421 }  // namespace bluetooth
422 }  // namespace OHOS