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 #ifndef LOG_TAG
16 #define LOG_TAG "bt_napi_hfp_ag"
17 #endif
18
19 #include "bluetooth_hfp_ag.h"
20
21 #include "bluetooth_utils.h"
22 #include "napi_async_work.h"
23 #include "napi_bluetooth_error.h"
24 #include "napi_bluetooth_hfp_ag.h"
25 #include "napi_bluetooth_profile.h"
26 #include "napi_bluetooth_event.h"
27 #include "napi_event_subscribe_module.h"
28 #include "hitrace_meter.h"
29
30 namespace OHOS {
31 namespace Bluetooth {
32 using namespace std;
33
34 std::shared_ptr<NapiHandsFreeAudioGatewayObserver> NapiHandsFreeAudioGateway::observer_ =
35 std::make_shared<NapiHandsFreeAudioGatewayObserver>();
36 bool NapiHandsFreeAudioGateway::isRegistered_ = false;
37 thread_local napi_ref NapiHandsFreeAudioGateway::consRef_ = nullptr;
38
DefineHandsFreeAudioGatewayJSClass(napi_env env,napi_value exports)39 void NapiHandsFreeAudioGateway::DefineHandsFreeAudioGatewayJSClass(napi_env env, napi_value exports)
40 {
41 napi_value constructor;
42 napi_property_descriptor properties[] = {
43 #ifdef BLUETOOTH_API_SINCE_10
44 DECLARE_NAPI_FUNCTION("getConnectedDevices", GetConnectionDevices),
45 DECLARE_NAPI_FUNCTION("getConnectionState", GetDeviceState),
46 #else
47 DECLARE_NAPI_FUNCTION("getConnectionDevices", GetConnectionDevices),
48 DECLARE_NAPI_FUNCTION("getDeviceState", GetDeviceState),
49 #endif
50 DECLARE_NAPI_FUNCTION("connect", Connect),
51 DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
52 DECLARE_NAPI_FUNCTION("getScoState", GetScoState),
53 DECLARE_NAPI_FUNCTION("connectSco", ConnectSco),
54 DECLARE_NAPI_FUNCTION("disconnectSco", DisconnectSco),
55 DECLARE_NAPI_FUNCTION("on", On),
56 DECLARE_NAPI_FUNCTION("off", Off),
57 DECLARE_NAPI_FUNCTION("openVoiceRecognition", OpenVoiceRecognition),
58 DECLARE_NAPI_FUNCTION("closeVoiceRecognition", CloseVoiceRecognition),
59 DECLARE_NAPI_FUNCTION("setConnectionStrategy", SetConnectionStrategy),
60 DECLARE_NAPI_FUNCTION("getConnectionStrategy", GetConnectionStrategy),
61 };
62
63 napi_define_class(env, "HandsFreeAudioGateway", NAPI_AUTO_LENGTH, HandsFreeAudioGatewayConstructor, nullptr,
64 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
65
66 #ifdef BLUETOOTH_API_SINCE_10
67 DefineCreateProfile(env, exports);
68 napi_create_reference(env, constructor, 1, &consRef_);
69 #else
70 napi_value napiProfile;
71 napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
72 NapiProfile::SetProfile(env, ProfileId::PROFILE_HANDS_FREE_AUDIO_GATEWAY, napiProfile);
73 #endif
74 }
75
DefineCreateProfile(napi_env env,napi_value exports)76 napi_value NapiHandsFreeAudioGateway::DefineCreateProfile(napi_env env, napi_value exports)
77 {
78 napi_property_descriptor properties[] = {
79 DECLARE_NAPI_FUNCTION("createHfpAgProfile", CreateHfpAgProfile),
80 };
81 HITRACE_METER_NAME(HITRACE_TAG_OHOS, "hfpag:napi_define_properties");
82 napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties);
83 return exports;
84 }
85
CreateHfpAgProfile(napi_env env,napi_callback_info info)86 napi_value NapiHandsFreeAudioGateway::CreateHfpAgProfile(napi_env env, napi_callback_info info)
87 {
88 HILOGI("enter");
89 napi_value napiProfile;
90 napi_value constructor = nullptr;
91 napi_get_reference_value(env, consRef_, &constructor);
92 napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
93 NapiProfile::SetProfile(env, ProfileId::PROFILE_HANDS_FREE_AUDIO_GATEWAY, napiProfile);
94 return napiProfile;
95 }
96
HandsFreeAudioGatewayConstructor(napi_env env,napi_callback_info info)97 napi_value NapiHandsFreeAudioGateway::HandsFreeAudioGatewayConstructor(napi_env env, napi_callback_info info)
98 {
99 napi_value thisVar = nullptr;
100 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
101 return thisVar;
102 }
103
On(napi_env env,napi_callback_info info)104 napi_value NapiHandsFreeAudioGateway::On(napi_env env, napi_callback_info info)
105 {
106 if (observer_) {
107 auto status = observer_->eventSubscribe_.Register(env, info);
108 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
109 }
110 if (!isRegistered_) {
111 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
112 profile->RegisterObserver(observer_);
113 isRegistered_ = true;
114 }
115 return NapiGetUndefinedRet(env);
116 }
117
Off(napi_env env,napi_callback_info info)118 napi_value NapiHandsFreeAudioGateway::Off(napi_env env, napi_callback_info info)
119 {
120 if (observer_) {
121 auto status = observer_->eventSubscribe_.Deregister(env, info);
122 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
123 }
124 return NapiGetUndefinedRet(env);
125 }
126
GetConnectionDevices(napi_env env,napi_callback_info info)127 napi_value NapiHandsFreeAudioGateway::GetConnectionDevices(napi_env env, napi_callback_info info)
128 {
129 HILOGI("enter");
130 napi_value ret = nullptr;
131 if (napi_create_array(env, &ret) != napi_ok) {
132 HILOGE("napi_create_array failed.");
133 }
134 napi_status checkRet = CheckEmptyParam(env, info);
135 NAPI_BT_ASSERT_RETURN(env, checkRet == napi_ok, BT_ERR_INVALID_PARAM, ret);
136
137 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
138 vector<BluetoothRemoteDevice> devices;
139 int errorCode = profile->GetConnectedDevices(devices);
140 HILOGI("errorCode:%{public}s, devices size:%{public}zu", GetErrorCode(errorCode).c_str(), devices.size());
141 NAPI_BT_ASSERT_RETURN(env, errorCode == BT_NO_ERROR, errorCode, ret);
142
143 vector<string> deviceVector;
144 for (auto &device: devices) {
145 deviceVector.push_back(device.GetDeviceAddr());
146 }
147 ConvertStringVectorToJS(env, ret, deviceVector);
148 return ret;
149 }
150
GetDeviceState(napi_env env,napi_callback_info info)151 napi_value NapiHandsFreeAudioGateway::GetDeviceState(napi_env env, napi_callback_info info)
152 {
153 HILOGD("enter");
154 napi_value result = nullptr;
155 int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED;
156 if (napi_create_int32(env, profileState, &result) != napi_ok) {
157 HILOGE("napi_create_int32 failed.");
158 }
159
160 std::string remoteAddr {};
161 bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
162 NAPI_BT_ASSERT_RETURN(env, checkRet, BT_ERR_INVALID_PARAM, result);
163
164 HandsFreeAudioGateway *profile = HandsFreeAudioGateway::GetProfile();
165 BluetoothRemoteDevice device(remoteAddr, BT_TRANSPORT_BREDR);
166 int32_t state = static_cast<int32_t>(BTConnectState::DISCONNECTED);
167 int32_t errorCode = profile->GetDeviceState(device, state);
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 HILOGD("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 HILOGD("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