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_hf"
17 #endif
18 
19 #include "napi_bluetooth_hfp_hf.h"
20 #include "napi_bluetooth_profile.h"
21 #include "bluetooth_errorcode.h"
22 #include "bluetooth_hfp_hf.h"
23 #include "napi_bluetooth_error.h"
24 #include "napi_bluetooth_event.h"
25 #include "napi_event_subscribe_module.h"
26 
27 namespace OHOS {
28 namespace Bluetooth {
29 using namespace std;
30 
31 std::shared_ptr<NapiHandsFreeUnitObserver> NapiHandsFreeUnit::observer_ =
32     std::make_shared<NapiHandsFreeUnitObserver>();
33 bool NapiHandsFreeUnit::isRegistered_ = false;
34 
DefineHandsFreeUnitJSClass(napi_env env)35 void NapiHandsFreeUnit::DefineHandsFreeUnitJSClass(napi_env env)
36 {
37     napi_value constructor;
38     napi_property_descriptor properties[] = {
39         DECLARE_NAPI_FUNCTION("on", On),
40         DECLARE_NAPI_FUNCTION("off", Off),
41         DECLARE_NAPI_FUNCTION("getConnectionDevices", GetConnectionDevices),
42         DECLARE_NAPI_FUNCTION("getDeviceState", GetDeviceState),
43         DECLARE_NAPI_FUNCTION("getScoState", GetScoState),
44         DECLARE_NAPI_FUNCTION("connect", Connect),
45         DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
46         DECLARE_NAPI_FUNCTION("connectSco", ConnectSco),
47         DECLARE_NAPI_FUNCTION("disconnectSco", DisconnectSco),
48         DECLARE_NAPI_FUNCTION("sendDTMF", SendDTMF),
49     };
50 
51     napi_define_class(env, "HandsFreeUnit", NAPI_AUTO_LENGTH, HandsFreeUnitConstructor, nullptr,
52         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
53 
54     napi_value napiProfile;
55     napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
56     NapiProfile::SetProfile(env, ProfileId::PROFILE_HANDS_FREE_UNIT, napiProfile);
57 }
58 
HandsFreeUnitConstructor(napi_env env,napi_callback_info info)59 napi_value NapiHandsFreeUnit::HandsFreeUnitConstructor(napi_env env, napi_callback_info info)
60 {
61     napi_value thisVar = nullptr;
62     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
63     return thisVar;
64 }
65 
On(napi_env env,napi_callback_info info)66 napi_value NapiHandsFreeUnit::On(napi_env env, napi_callback_info info)
67 {
68     if (observer_) {
69         auto status = observer_->eventSubscribe_.Register(env, info);
70         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
71     }
72     if (!isRegistered_) {
73         HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
74         profile->RegisterObserver(observer_);
75         isRegistered_ = true;
76     }
77     return NapiGetUndefinedRet(env);
78 }
79 
Off(napi_env env,napi_callback_info info)80 napi_value NapiHandsFreeUnit::Off(napi_env env, napi_callback_info info)
81 {
82     if (observer_) {
83         auto status = observer_->eventSubscribe_.Deregister(env, info);
84         NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
85     }
86     return NapiGetUndefinedRet(env);
87 }
88 
GetConnectionDevices(napi_env env,napi_callback_info info)89 napi_value NapiHandsFreeUnit::GetConnectionDevices(napi_env env, napi_callback_info info)
90 {
91     HILOGI("enter");
92     napi_value ret = nullptr;
93     napi_create_array(env, &ret);
94     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
95     vector<int> states = { static_cast<int>(BTConnectState::CONNECTED) };
96     vector<BluetoothRemoteDevice> devices = profile->GetDevicesByStates(states);
97     vector<string> deviceVector;
98     for (auto &device: devices) {
99         deviceVector.push_back(device.GetDeviceAddr());
100     }
101     ConvertStringVectorToJS(env, ret, deviceVector);
102     return ret;
103 }
104 
GetDeviceState(napi_env env,napi_callback_info info)105 napi_value NapiHandsFreeUnit::GetDeviceState(napi_env env, napi_callback_info info)
106 {
107     HILOGI("enter");
108     size_t expectedArgsCount = ARGS_SIZE_ONE;
109     size_t argc = expectedArgsCount;
110     napi_value argv[ARGS_SIZE_ONE] = {0};
111     napi_value thisVar = nullptr;
112 
113     napi_value ret = nullptr;
114     napi_get_undefined(env, &ret);
115 
116     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
117     if (argc != expectedArgsCount) {
118         HILOGE("Requires 1 argument.");
119         return ret;
120     }
121     string deviceId;
122     if (!ParseString(env, deviceId, argv[PARAM0])) {
123         HILOGE("string expected.");
124         return ret;
125     }
126 
127     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
128     BluetoothRemoteDevice device(deviceId, 1);
129     int state = profile->GetDeviceState(device);
130     int status = GetProfileConnectionState(state);
131     napi_value result = nullptr;
132     napi_create_int32(env, status, &result);
133     HILOGI("status: %{public}d", status);
134     return result;
135 }
136 
GetScoState(napi_env env,napi_callback_info info)137 napi_value NapiHandsFreeUnit::GetScoState(napi_env env, napi_callback_info info)
138 {
139     HILOGI("enter");
140     size_t expectedArgsCount = ARGS_SIZE_ONE;
141     size_t argc = expectedArgsCount;
142     napi_value argv[ARGS_SIZE_ONE] = {0};
143     napi_value thisVar = nullptr;
144 
145     napi_value ret = nullptr;
146     napi_get_undefined(env, &ret);
147 
148     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
149     if (argc != expectedArgsCount) {
150         HILOGE("Requires 1 argument.");
151         return ret;
152     }
153     string deviceId;
154     if (!ParseString(env, deviceId, argv[PARAM0])) {
155         HILOGE("string expected.");
156         return ret;
157     }
158 
159     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
160     BluetoothRemoteDevice device(deviceId, 1);
161     int state = profile->GetScoState(device);
162     int status = GetScoConnectionState(state);
163     napi_value result = nullptr;
164     napi_create_int32(env, status, &result);
165     HILOGI("status: %{public}d", status);
166     return result;
167 }
168 
Connect(napi_env env,napi_callback_info info)169 napi_value NapiHandsFreeUnit::Connect(napi_env env, napi_callback_info info)
170 {
171     HILOGI("enter");
172     size_t expectedArgsCount = ARGS_SIZE_ONE;
173     size_t argc = expectedArgsCount;
174     napi_value argv[ARGS_SIZE_ONE] = {0};
175     napi_value thisVar = nullptr;
176 
177     napi_value ret = nullptr;
178     napi_get_undefined(env, &ret);
179 
180     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
181     if (argc != expectedArgsCount) {
182         HILOGE("Requires 1 argument.");
183         return ret;
184     }
185     string deviceId;
186     if (!ParseString(env, deviceId, argv[PARAM0])) {
187         HILOGE("string expected.");
188         return ret;
189     }
190 
191     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
192     BluetoothRemoteDevice device(deviceId, 1);
193     bool isOK = profile->Connect(device);
194     napi_value result = nullptr;
195     napi_get_boolean(env, isOK, &result);
196     HILOGI("res: %{public}d", isOK);
197     return result;
198 }
199 
Disconnect(napi_env env,napi_callback_info info)200 napi_value NapiHandsFreeUnit::Disconnect(napi_env env, napi_callback_info info)
201 {
202     HILOGI("enter");
203     size_t expectedArgsCount = ARGS_SIZE_ONE;
204     size_t argc = expectedArgsCount;
205     napi_value argv[ARGS_SIZE_ONE] = {0};
206     napi_value thisVar = nullptr;
207 
208     napi_value ret = nullptr;
209     napi_get_undefined(env, &ret);
210 
211     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
212     if (argc != expectedArgsCount) {
213         HILOGE("Requires 1 argument.");
214         return ret;
215     }
216     string deviceId;
217     if (!ParseString(env, deviceId, argv[PARAM0])) {
218         HILOGE("string expected.");
219         return ret;
220     }
221 
222     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
223     BluetoothRemoteDevice device(deviceId, 1);
224     bool isOK = profile->Disconnect(device);
225     napi_value result = nullptr;
226     napi_get_boolean(env, isOK, &result);
227     HILOGI("res: %{public}d", isOK);
228     return result;
229 }
230 
ConnectSco(napi_env env,napi_callback_info info)231 napi_value NapiHandsFreeUnit::ConnectSco(napi_env env, napi_callback_info info)
232 {
233     HILOGI("enter");
234     size_t expectedArgsCount = ARGS_SIZE_ONE;
235     size_t argc = expectedArgsCount;
236     napi_value argv[ARGS_SIZE_ONE] = {0};
237     napi_value thisVar = nullptr;
238 
239     napi_value ret = nullptr;
240     napi_get_undefined(env, &ret);
241 
242     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
243     if (argc != expectedArgsCount) {
244         HILOGE("Requires 1 argument.");
245         return ret;
246     }
247     string deviceId;
248     if (!ParseString(env, deviceId, argv[PARAM0])) {
249         HILOGE("string expected.");
250         return ret;
251     }
252 
253     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
254     BluetoothRemoteDevice device(deviceId, 1);
255     bool isOK = profile->ConnectSco(device);
256     napi_value result = nullptr;
257     napi_get_boolean(env, isOK, &result);
258     HILOGI("res: %{public}d", isOK);
259     return result;
260 }
261 
DisconnectSco(napi_env env,napi_callback_info info)262 napi_value NapiHandsFreeUnit::DisconnectSco(napi_env env, napi_callback_info info)
263 {
264     HILOGI("enter");
265     size_t expectedArgsCount = ARGS_SIZE_ONE;
266     size_t argc = expectedArgsCount;
267     napi_value argv[ARGS_SIZE_ONE] = {0};
268     napi_value thisVar = nullptr;
269 
270     napi_value ret = nullptr;
271     napi_get_undefined(env, &ret);
272 
273     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
274     if (argc != expectedArgsCount) {
275         HILOGE("Requires 1 argument.");
276         return ret;
277     }
278     string deviceId;
279     if (!ParseString(env, deviceId, argv[PARAM0])) {
280         HILOGE("string expected.");
281         return ret;
282     }
283 
284     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
285     BluetoothRemoteDevice device(deviceId, 1);
286     bool isOK = profile->DisconnectSco(device);
287     napi_value result = nullptr;
288     napi_get_boolean(env, isOK, &result);
289     HILOGI("res: %{public}d", isOK);
290     return result;
291 }
292 
SendDTMF(napi_env env,napi_callback_info info)293 napi_value NapiHandsFreeUnit::SendDTMF(napi_env env, napi_callback_info info)
294 {
295     HILOGI("enter");
296     size_t expectedArgsCount = ARGS_SIZE_TWO;
297     size_t argc = expectedArgsCount;
298     napi_value argv[ARGS_SIZE_TWO] = {0};
299     napi_value thisVar = nullptr;
300 
301     napi_value ret = nullptr;
302     napi_get_undefined(env, &ret);
303 
304     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
305     if (argc != expectedArgsCount) {
306         HILOGE("Requires 2 argument.");
307         return ret;
308     }
309     string deviceId;
310     if (!ParseString(env, deviceId, argv[PARAM0])) {
311         HILOGE("string expected.");
312         return ret;
313     }
314     int code;
315     if (ParseInt32(env, code, argv[PARAM1])) {
316         HILOGE("int32 expected.");
317         return ret;
318     }
319 
320     HandsFreeUnit *profile = HandsFreeUnit::GetProfile();
321     BluetoothRemoteDevice device(deviceId, 1);
322     bool isOK = profile->SendDTMFTone(device, code);
323     napi_value result = nullptr;
324     napi_get_boolean(env, isOK, &result);
325     HILOGI("res: %{public}d", isOK);
326     return result;
327 }
328 
329 } // namespace Bluetooth
330 } // namespace OHOS