• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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