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