1 /*
2 * Copyright (C) 2021-2022 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 #include "bluetooth_hfp_ag.h"
16
17 #include "bluetooth_errorcode.h"
18 #include "bluetooth_utils.h"
19 #include "napi_async_work.h"
20 #include "napi_bluetooth_error.h"
21 #include "napi_bluetooth_hfp_ag.h"
22 #include "napi_bluetooth_profile.h"
23 #include "napi_bluetooth_event.h"
24
25 namespace OHOS {
26 namespace Bluetooth {
27 using namespace std;
28
29 NapiHandsFreeAudioGatewayObserver NapiHandsFreeAudioGateway::observer_;
30 bool NapiHandsFreeAudioGateway::isRegistered_ = false;
31 thread_local napi_ref NapiHandsFreeAudioGateway::consRef_ = nullptr;
32
DefineHandsFreeAudioGatewayJSClass(napi_env env,napi_value exports)33 void NapiHandsFreeAudioGateway::DefineHandsFreeAudioGatewayJSClass(napi_env env, napi_value exports)
34 {
35 napi_value constructor;
36 napi_property_descriptor properties[] = {
37 #ifdef BLUETOOTH_API_SINCE_10
38 DECLARE_NAPI_FUNCTION("getConnectedDevices", GetConnectionDevices),
39 DECLARE_NAPI_FUNCTION("getConnectionState", GetDeviceState),
40 #else
41 DECLARE_NAPI_FUNCTION("getConnectionDevices", GetConnectionDevices),
42 DECLARE_NAPI_FUNCTION("getDeviceState", GetDeviceState),
43 #endif
44 DECLARE_NAPI_FUNCTION("connect", Connect),
45 DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
46 DECLARE_NAPI_FUNCTION("getScoState", GetScoState),
47 DECLARE_NAPI_FUNCTION("connectSco", ConnectSco),
48 DECLARE_NAPI_FUNCTION("disconnectSco", DisconnectSco),
49 DECLARE_NAPI_FUNCTION("on", On),
50 DECLARE_NAPI_FUNCTION("off", Off),
51 DECLARE_NAPI_FUNCTION("openVoiceRecognition", OpenVoiceRecognition),
52 DECLARE_NAPI_FUNCTION("closeVoiceRecognition", CloseVoiceRecognition),
53 DECLARE_NAPI_FUNCTION("setConnectionStrategy", SetConnectionStrategy),
54 DECLARE_NAPI_FUNCTION("getConnectionStrategy", GetConnectionStrategy),
55 };
56
57 napi_define_class(env, "HandsFreeAudioGateway", NAPI_AUTO_LENGTH, HandsFreeAudioGatewayConstructor, nullptr,
58 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
59
60 #ifdef BLUETOOTH_API_SINCE_10
61 DefineCreateProfile(env, exports);
62 napi_create_reference(env, constructor, 1, &consRef_);
63 #else
64 napi_value napiProfile;
65 napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
66 NapiProfile::SetProfile(env, ProfileId::PROFILE_HANDS_FREE_AUDIO_GATEWAY, napiProfile);
67 #endif
68 HILOGI("finished");
69 }
70
DefineCreateProfile(napi_env env,napi_value exports)71 napi_value NapiHandsFreeAudioGateway::DefineCreateProfile(napi_env env, napi_value exports)
72 {
73 napi_property_descriptor properties[] = {
74 DECLARE_NAPI_FUNCTION("createHfpAgProfile", CreateHfpAgProfile),
75 };
76 napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties);
77 return exports;
78 }
79
CreateHfpAgProfile(napi_env env,napi_callback_info info)80 napi_value NapiHandsFreeAudioGateway::CreateHfpAgProfile(napi_env env, napi_callback_info info)
81 {
82 HILOGI("enter");
83 napi_value napiProfile;
84 napi_value constructor = nullptr;
85 napi_get_reference_value(env, consRef_, &constructor);
86 napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
87 NapiProfile::SetProfile(env, ProfileId::PROFILE_HANDS_FREE_AUDIO_GATEWAY, napiProfile);
88 return napiProfile;
89 }
90
HandsFreeAudioGatewayConstructor(napi_env env,napi_callback_info info)91 napi_value NapiHandsFreeAudioGateway::HandsFreeAudioGatewayConstructor(napi_env env, napi_callback_info info)
92 {
93 napi_value thisVar = nullptr;
94 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
95 return thisVar;
96 }
97
On(napi_env env,napi_callback_info info)98 napi_value NapiHandsFreeAudioGateway::On(napi_env env, napi_callback_info info)
99 {
100 HILOGI("enter");
101 std::unique_lock<std::shared_mutex> guard(NapiHandsFreeAudioGatewayObserver::g_handsFreeAudioGatewayCallbackMutex);
102
103 napi_value ret = nullptr;
104 ret = NapiEvent::OnEvent(env, info, observer_.callbackInfos_);
105 if (!isRegistered_) {
106 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
107 profile->RegisterObserver(&observer_);
108 isRegistered_ = true;
109 }
110
111 HILOGI("Hands Free Audio Gateway is registered");
112 return ret;
113 }
114
Off(napi_env env,napi_callback_info info)115 napi_value NapiHandsFreeAudioGateway::Off(napi_env env, napi_callback_info info)
116 {
117 HILOGI("enter");
118 std::unique_lock<std::shared_mutex> guard(NapiHandsFreeAudioGatewayObserver::g_handsFreeAudioGatewayCallbackMutex);
119
120 napi_value ret = nullptr;
121 ret = NapiEvent::OffEvent(env, info, observer_.callbackInfos_);
122 HILOGI("Hands Free Audio Gateway is unregistered");
123 return ret;
124 }
125
GetConnectionDevices(napi_env env,napi_callback_info info)126 napi_value NapiHandsFreeAudioGateway::GetConnectionDevices(napi_env env, napi_callback_info info)
127 {
128 HILOGI("enter");
129 napi_value ret = nullptr;
130 if (napi_create_array(env, &ret) != napi_ok) {
131 HILOGE("napi_create_array failed.");
132 }
133 napi_status checkRet = CheckEmptyParam(env, info);
134 NAPI_BT_ASSERT_RETURN(env, checkRet == napi_ok, BT_ERR_INVALID_PARAM, ret);
135
136 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
137 vector<BluetoothRemoteDevice> devices;
138 int errorCode = profile->GetConnectedDevices(devices);
139 HILOGI("errorCode:%{public}s, devices size:%{public}zu", GetErrorCode(errorCode).c_str(), devices.size());
140 NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, ret);
141
142 vector<string> deviceVector;
143 for (auto &device: devices) {
144 deviceVector.push_back(device.GetDeviceAddr());
145 }
146 ConvertStringVectorToJS(env, ret, deviceVector);
147 return ret;
148 }
149
GetDeviceState(napi_env env,napi_callback_info info)150 napi_value NapiHandsFreeAudioGateway::GetDeviceState(napi_env env, napi_callback_info info)
151 {
152 HILOGI("enter");
153 napi_value result = nullptr;
154 int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED;
155 if (napi_create_int32(env, profileState, &result) != napi_ok) {
156 HILOGE("napi_create_int32 failed.");
157 }
158
159 std::string remoteAddr {};
160 bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
161 NAPI_BT_ASSERT_RETURN(env, checkRet, BT_ERR_INVALID_PARAM, result);
162
163 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
164 BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
165 int32_t state = static_cast<int32_t>(BTConnectState::DISCONNECTED);
166 int32_t errorCode = profile->GetDeviceState(device, state);
167 HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
168 NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, result);
169
170 profileState = GetProfileConnectionState(state);
171 if (napi_create_int32(env, profileState, &result) != napi_ok) {
172 HILOGE("napi_create_int32 failed.");
173 }
174 return result;
175 }
176
GetScoState(napi_env env,napi_callback_info info)177 napi_value NapiHandsFreeAudioGateway::GetScoState(napi_env env, napi_callback_info info)
178 {
179 HILOGI("enter");
180 size_t expectedArgsCount = ARGS_SIZE_ONE;
181 size_t argc = expectedArgsCount;
182 napi_value argv[ARGS_SIZE_ONE] = {0};
183 napi_value thisVar = nullptr;
184
185 napi_value ret = nullptr;
186 napi_get_undefined(env, &ret);
187
188 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
189 if (argc != expectedArgsCount) {
190 HILOGE("Requires 1 argument.");
191 return ret;
192 }
193 string deviceId;
194 if (!ParseString(env, deviceId, argv[PARAM0])) {
195 HILOGE("string expected.");
196 return ret;
197 }
198
199 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
200 BluetoothRemoteDevice device(deviceId, 1);
201 int state = profile->GetScoState(device);
202 int status = GetScoConnectionState(state);
203 napi_value result = nullptr;
204 napi_create_int32(env, status, &result);
205 HILOGI("status: %{public}d", status);
206 return result;
207 }
208
ConnectSco(napi_env env,napi_callback_info info)209 napi_value NapiHandsFreeAudioGateway::ConnectSco(napi_env env, napi_callback_info info)
210 {
211 HILOGI("enter");
212 size_t expectedArgsCount = ARGS_SIZE_ONE;
213 size_t argc = expectedArgsCount;
214 napi_value argv[ARGS_SIZE_ONE] = {0};
215 napi_value thisVar = nullptr;
216
217 napi_value ret = nullptr;
218 napi_get_undefined(env, &ret);
219
220 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
221 if (argc != expectedArgsCount) {
222 HILOGE("Requires 1 argument.");
223 return ret;
224 }
225 string deviceId;
226 if (!ParseString(env, deviceId, argv[PARAM0])) {
227 HILOGE("string expected.");
228 return ret;
229 }
230
231 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
232 BluetoothRemoteDevice device(deviceId, 1);
233 bool isOK = profile->SetActiveDevice(device);
234 if (isOK) {
235 isOK = profile->ConnectSco();
236 }
237 napi_value result = nullptr;
238 napi_get_boolean(env, isOK, &result);
239 HILOGI("res: %{public}d", isOK);
240 return result;
241 }
242
DisconnectSco(napi_env env,napi_callback_info info)243 napi_value NapiHandsFreeAudioGateway::DisconnectSco(napi_env env, napi_callback_info info)
244 {
245 HILOGI("enter");
246 size_t expectedArgsCount = ARGS_SIZE_ONE;
247 size_t argc = expectedArgsCount;
248 napi_value argv[ARGS_SIZE_ONE] = {0};
249 napi_value thisVar = nullptr;
250
251 napi_value ret = nullptr;
252 napi_get_undefined(env, &ret);
253
254 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
255 if (argc != expectedArgsCount) {
256 HILOGE("Requires 1 argument.");
257 return ret;
258 }
259 string deviceId;
260 if (!ParseString(env, deviceId, argv[PARAM0])) {
261 HILOGE("string expected.");
262 return ret;
263 }
264
265 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
266 BluetoothRemoteDevice device(deviceId, 1);
267 bool isOK = profile->SetActiveDevice(device);
268 if (isOK) {
269 isOK = profile->DisconnectSco();
270 }
271 napi_value result = nullptr;
272 napi_get_boolean(env, isOK, &result);
273 HILOGI("res: %{public}d", isOK);
274 return result;
275 }
276
OpenVoiceRecognition(napi_env env,napi_callback_info info)277 napi_value NapiHandsFreeAudioGateway::OpenVoiceRecognition(napi_env env, napi_callback_info info)
278 {
279 HILOGI("enter");
280 size_t expectedArgsCount = ARGS_SIZE_ONE;
281 size_t argc = expectedArgsCount;
282 napi_value argv[ARGS_SIZE_ONE] = {0};
283 napi_value thisVar = nullptr;
284
285 napi_value ret = nullptr;
286 napi_get_undefined(env, &ret);
287
288 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
289 if (argc != expectedArgsCount) {
290 HILOGE("Requires 1 argument.");
291 return ret;
292 }
293 string deviceId;
294 if (!ParseString(env, deviceId, argv[PARAM0])) {
295 HILOGE("string expected.");
296 return ret;
297 }
298
299 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
300 BluetoothRemoteDevice device(deviceId, 1);
301 bool isOK = profile->OpenVoiceRecognition(device);
302 napi_value result = nullptr;
303 napi_get_boolean(env, isOK, &result);
304 HILOGI("res: %{public}d", isOK);
305 return result;
306 }
307
CloseVoiceRecognition(napi_env env,napi_callback_info info)308 napi_value NapiHandsFreeAudioGateway::CloseVoiceRecognition(napi_env env, napi_callback_info info)
309 {
310 HILOGI("enter");
311 size_t expectedArgsCount = ARGS_SIZE_ONE;
312 size_t argc = expectedArgsCount;
313 napi_value argv[ARGS_SIZE_ONE] = {0};
314 napi_value thisVar = nullptr;
315
316 napi_value ret = nullptr;
317 napi_get_undefined(env, &ret);
318
319 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
320 if (argc != expectedArgsCount) {
321 HILOGE("Requires 1 argument.");
322 return ret;
323 }
324 string deviceId;
325 if (!ParseString(env, deviceId, argv[PARAM0])) {
326 HILOGE("string expected.");
327 return ret;
328 }
329
330 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
331 BluetoothRemoteDevice device(deviceId, 1);
332 bool isOK = profile->CloseVoiceRecognition(device);
333 napi_value result = nullptr;
334 napi_get_boolean(env, isOK, &result);
335 HILOGI("res: %{public}d", isOK);
336 return result;
337 }
338
Connect(napi_env env,napi_callback_info info)339 napi_value NapiHandsFreeAudioGateway::Connect(napi_env env, napi_callback_info info)
340 {
341 HILOGI("enter");
342 std::string remoteAddr {};
343 bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
344 NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
345
346 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
347 BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
348 int32_t errorCode = profile->Connect(device);
349 HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
350 NAPI_BT_ASSERT_RETURN_FALSE(env, errorCode == BT_NO_ERROR, errorCode);
351 return NapiGetBooleanTrue(env);
352 }
353
Disconnect(napi_env env,napi_callback_info info)354 napi_value NapiHandsFreeAudioGateway::Disconnect(napi_env env, napi_callback_info info)
355 {
356 HILOGI("enter");
357 std::string remoteAddr {};
358 bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
359 NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
360
361 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
362 BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
363 int32_t errorCode = profile->Disconnect(device);
364 HILOGI("errorCode:%{public}s", GetErrorCode(errorCode).c_str());
365 NAPI_BT_ASSERT_RETURN_FALSE(env, errorCode == BT_NO_ERROR, errorCode);
366 return NapiGetBooleanTrue(env);
367 }
368
SetConnectionStrategy(napi_env env,napi_callback_info info)369 napi_value NapiHandsFreeAudioGateway::SetConnectionStrategy(napi_env env, napi_callback_info info)
370 {
371 HILOGI("start");
372 std::string remoteAddr {};
373 int32_t strategy = 0;
374 auto status = CheckSetConnectStrategyParam(env, info, remoteAddr, strategy);
375 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
376
377 auto func = [remoteAddr, strategy]() {
378 BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
379 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
380 int32_t err = profile->SetConnectStrategy(remoteDevice, strategy);
381 HILOGI("err: %{public}d", err);
382 return NapiAsyncWorkRet(err);
383 };
384 auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
385 NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
386 asyncWork->Run();
387 return asyncWork->GetRet();
388 }
389
GetConnectionStrategy(napi_env env,napi_callback_info info)390 napi_value NapiHandsFreeAudioGateway::GetConnectionStrategy(napi_env env, napi_callback_info info)
391 {
392 HILOGI("start");
393 std::string remoteAddr {};
394 auto status = CheckDeviceAddressParam(env, info, remoteAddr);
395 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
396
397 auto func = [remoteAddr]() {
398 int strategy = 0;
399 BluetoothRemoteDevice remoteDevice(remoteAddr, BT_TRANSPORT_BREDR);
400 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
401 int32_t err = profile->GetConnectStrategy(remoteDevice, strategy);
402 HILOGI("err: %{public}d, deviceName: %{public}d", err, strategy);
403 auto object = std::make_shared<NapiNativeInt>(strategy);
404 return NapiAsyncWorkRet(err, object);
405 };
406 auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
407 NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
408 asyncWork->Run();
409 return asyncWork->GetRet();
410 }
411 } // namespace Bluetooth
412 } // namespace OHOS