1 /*
2 * Copyright (C) 2023 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_a2dp_src.h"
16 #include "bluetooth_errorcode.h"
17 #include "napi_async_work.h"
18 #include "napi_bluetooth_profile.h"
19 #include "napi_bluetooth_a2dp_src.h"
20 #include "napi_bluetooth_event.h"
21 #include "napi_bluetooth_error.h"
22 #include "napi_bluetooth_host.h"
23 #include "napi_bluetooth_utils.h"
24
25 namespace OHOS {
26 namespace Bluetooth {
27 using namespace std;
28
29 NapiA2dpSourceObserver NapiA2dpSource::observer_;
30 bool NapiA2dpSource::isRegistered_ = false;
31 thread_local napi_ref g_napiProfile = nullptr;
32
DefineA2dpSourceJSClass(napi_env env,napi_value exports)33 napi_value NapiA2dpSource::DefineA2dpSourceJSClass(napi_env env, napi_value exports)
34 {
35 A2dpPropertyValueInit(env, exports);
36 napi_property_descriptor properties[] = {
37 DECLARE_NAPI_FUNCTION("on", On),
38 DECLARE_NAPI_FUNCTION("off", Off),
39 DECLARE_NAPI_FUNCTION("connect", Connect),
40 DECLARE_NAPI_FUNCTION("disconnect", Disconnect),
41 DECLARE_NAPI_FUNCTION("getPlayingState", GetPlayingState),
42 #ifndef BLUETOOTH_API_SINCE_10
43 DECLARE_NAPI_FUNCTION("getConnectionDevices", GetConnectionDevices),
44 DECLARE_NAPI_FUNCTION("getDeviceState", GetDeviceState),
45 #endif
46 #ifdef BLUETOOTH_API_SINCE_10
47 DECLARE_NAPI_FUNCTION("setConnectionStrategy", SetConnectionStrategy),
48 DECLARE_NAPI_FUNCTION("getConnectionStrategy", GetConnectionStrategy),
49 DECLARE_NAPI_FUNCTION("getConnectionState", GetConnectionState),
50 DECLARE_NAPI_FUNCTION("getConnectedDevices", getConnectedDevices),
51 #endif
52 };
53
54 napi_value constructor;
55 napi_define_class(env,
56 "A2dpSource",
57 NAPI_AUTO_LENGTH,
58 A2dpSourceConstructor,
59 nullptr,
60 sizeof(properties) / sizeof(properties[0]),
61 properties,
62 &constructor);
63 #ifdef BLUETOOTH_API_SINCE_10
64 DefineCreateProfile(env, exports);
65 napi_create_reference(env, constructor, 1, &g_napiProfile);
66 #else
67 napi_value napiProfile;
68 napi_new_instance(env, constructor, 0, nullptr, &napiProfile);
69 NapiProfile::SetProfile(env, ProfileId::PROFILE_A2DP_SOURCE, napiProfile);
70 #endif
71 HILOGI("finished");
72 return exports;
73 }
74
A2dpSourceConstructor(napi_env env,napi_callback_info info)75 napi_value NapiA2dpSource::A2dpSourceConstructor(napi_env env, napi_callback_info info)
76 {
77 napi_value thisVar = nullptr;
78 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
79 return thisVar;
80 }
81
On(napi_env env,napi_callback_info info)82 napi_value NapiA2dpSource::On(napi_env env, napi_callback_info info)
83 {
84 HILOGI("enter");
85 std::unique_lock<std::shared_mutex> guard(NapiA2dpSourceObserver::g_a2dpSrcCallbackInfosMutex);
86
87 napi_value ret = nullptr;
88 ret = NapiEvent::OnEvent(env, info, observer_.callbackInfos_);
89 if (!isRegistered_) {
90 A2dpSource *profile = A2dpSource::GetProfile();
91 profile->RegisterObserver(&observer_);
92 isRegistered_ = true;
93 }
94 HILOGI("napi A2dpSource is registered");
95 return ret;
96 }
97
Off(napi_env env,napi_callback_info info)98 napi_value NapiA2dpSource::Off(napi_env env, napi_callback_info info)
99 {
100 HILOGI("enter");
101 std::unique_lock<std::shared_mutex> guard(NapiA2dpSourceObserver::g_a2dpSrcCallbackInfosMutex);
102
103 napi_value ret = nullptr;
104 ret = NapiEvent::OffEvent(env, info, observer_.callbackInfos_);
105 HILOGI("Napi A2dpSource is unregistered");
106 return ret;
107 }
108
GetPlayingState(napi_env env,napi_callback_info info)109 napi_value NapiA2dpSource::GetPlayingState(napi_env env, napi_callback_info info)
110 {
111 HILOGI("start");
112 int state = PlayingState::STATE_NOT_PLAYING;
113 napi_value ret = nullptr;
114 napi_create_int32(env, state, &ret);
115
116 std::string remoteAddr{};
117 bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
118 NAPI_BT_ASSERT_RETURN(env, checkRet, BT_ERR_INVALID_PARAM, ret);
119
120 int transport = BT_TRANSPORT_BREDR;
121 BluetoothRemoteDevice remoteDevice = BluetoothRemoteDevice(remoteAddr, transport);
122 A2dpSource *profile = A2dpSource::GetProfile();
123 int32_t errorCode = profile->GetPlayingState(remoteDevice, state);
124 HILOGI("errorCode: %{public}d", errorCode);
125 NAPI_BT_ASSERT_RETURN(env, (errorCode == BT_NO_ERROR), errorCode, ret);
126
127 return NapiGetInt32Ret(env, state);
128 }
129
Connect(napi_env env,napi_callback_info info)130 napi_value NapiA2dpSource::Connect(napi_env env, napi_callback_info info)
131 {
132 HILOGI("start");
133 std::string remoteAddr{};
134 bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
135 NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
136
137 int transport = BT_TRANSPORT_BREDR;
138 BluetoothRemoteDevice remoteDevice = BluetoothRemoteDevice(remoteAddr, transport);
139 A2dpSource *profile = A2dpSource::GetProfile();
140 int32_t ret = profile->Connect(remoteDevice);
141 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
142
143 return NapiGetBooleanTrue(env);
144 }
145
Disconnect(napi_env env,napi_callback_info info)146 napi_value NapiA2dpSource::Disconnect(napi_env env, napi_callback_info info)
147 {
148 HILOGI("start");
149 std::string remoteAddr{};
150 bool checkRet = CheckDeivceIdParam(env, info, remoteAddr);
151 NAPI_BT_ASSERT_RETURN_FALSE(env, checkRet, BT_ERR_INVALID_PARAM);
152
153 int transport = BT_TRANSPORT_BREDR;
154 BluetoothRemoteDevice remoteDevice = BluetoothRemoteDevice(remoteAddr, transport);
155 A2dpSource *profile = A2dpSource::GetProfile();
156 int32_t ret = profile->Disconnect(remoteDevice);
157 NAPI_BT_ASSERT_RETURN_FALSE(env, ret == BT_NO_ERROR, ret);
158
159 return NapiGetBooleanTrue(env);
160 }
161
PlayingStateInit(napi_env env)162 napi_value PlayingStateInit(napi_env env)
163 {
164 HILOGI("enter");
165 napi_value playingState = nullptr;
166 napi_create_object(env, &playingState);
167 SetNamedPropertyByInteger(env, playingState, PlayingState::STATE_NOT_PLAYING, "STATE_NOT_PLAYING");
168 SetNamedPropertyByInteger(env, playingState, PlayingState::STATE_PLAYING, "STATE_PLAYING");
169 return playingState;
170 }
171
A2dpPropertyValueInit(napi_env env,napi_value exports)172 napi_value NapiA2dpSource::A2dpPropertyValueInit(napi_env env, napi_value exports)
173 {
174 napi_value playingStateObj = PlayingStateInit(env);
175 napi_property_descriptor exportProps[] = {
176 DECLARE_NAPI_PROPERTY("PlayingState", playingStateObj),
177 };
178 napi_define_properties(env, exports, sizeof(exportProps) / sizeof(*exportProps), exportProps);
179 HILOGI("end");
180 return exports;
181 }
182
GetConnectionDevices(napi_env env,napi_callback_info info)183 napi_value NapiA2dpSource::GetConnectionDevices(napi_env env, napi_callback_info info)
184 {
185 HILOGI("enter");
186 napi_value ret = nullptr;
187 napi_create_array(env, &ret);
188 A2dpSource *profile = A2dpSource::GetProfile();
189 vector<int> states;
190 states.push_back(1);
191 vector<BluetoothRemoteDevice> devices;
192 int errorCode = profile->GetDevicesByStates(states, devices);
193 NAPI_BT_ASSERT_RETURN(env, (errorCode == BT_NO_ERROR), errorCode, ret);
194
195 vector<string> deviceVector;
196 for (auto &device : devices) {
197 deviceVector.push_back(device.GetDeviceAddr());
198 }
199 ConvertStringVectorToJS(env, ret, deviceVector);
200 return ret;
201 }
202
GetDeviceState(napi_env env,napi_callback_info info)203 napi_value NapiA2dpSource::GetDeviceState(napi_env env, napi_callback_info info)
204 {
205 HILOGI("enter");
206
207 size_t expectedArgsCount = ARGS_SIZE_ONE;
208 size_t argc = expectedArgsCount;
209 napi_value argv[ARGS_SIZE_ONE] = {0};
210 napi_value thisVar = nullptr;
211
212 napi_value ret = nullptr;
213 napi_get_undefined(env, &ret);
214
215 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
216 if (argc != expectedArgsCount) {
217 HILOGE("Requires 1 argument.");
218 return ret;
219 }
220 string deviceId;
221 if (!ParseString(env, deviceId, argv[PARAM0])) {
222 HILOGE("string expected.");
223 return ret;
224 }
225
226 A2dpSource *profile = A2dpSource::GetProfile();
227 BluetoothRemoteDevice device(deviceId, 1);
228
229 int32_t profileState = ProfileConnectionState::STATE_DISCONNECTED;
230 if (napi_create_int32(env, profileState, &ret) != napi_ok) {
231 HILOGE("napi_create_int32 failed.");
232 }
233
234 int btConnectState = static_cast<int32_t>(BTConnectState::DISCONNECTED);
235 int errorCode = profile->GetDeviceState(device, btConnectState);
236 NAPI_BT_ASSERT_RETURN(env, (errorCode == BT_NO_ERROR), errorCode, ret);
237
238 napi_value result = nullptr;
239 int status = GetProfileConnectionState(btConnectState);
240 napi_create_int32(env, status, &result);
241 HILOGI("status: %{public}d", status);
242 return result;
243 }
244
245 #ifdef BLUETOOTH_API_SINCE_10
DefineCreateProfile(napi_env env,napi_value exports)246 napi_value NapiA2dpSource::DefineCreateProfile(napi_env env, napi_value exports)
247 {
248 napi_property_descriptor properties[] = {
249 DECLARE_NAPI_FUNCTION("createA2dpSrcProfile", CreateA2dpSrcProfile),
250 };
251 napi_define_properties(env, exports, sizeof(properties) / sizeof(properties[0]), properties);
252 return exports;
253 }
254
CreateA2dpSrcProfile(napi_env env,napi_callback_info info)255 napi_value NapiA2dpSource::CreateA2dpSrcProfile(napi_env env, napi_callback_info info)
256 {
257 napi_value profile;
258 napi_value constructor = nullptr;
259 napi_get_reference_value(env, g_napiProfile, &constructor);
260 napi_new_instance(env, constructor, 0, nullptr, &profile);
261 return profile;
262 }
263
SetConnectionStrategy(napi_env env,napi_callback_info info)264 napi_value NapiA2dpSource::SetConnectionStrategy(napi_env env, napi_callback_info info)
265 {
266 HILOGI("start");
267 std::string remoteAddr{};
268 int32_t strategy = 0;
269 auto status = CheckSetConnectStrategyParam(env, info, remoteAddr, strategy);
270 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
271
272 int transport = BT_TRANSPORT_BREDR;
273 auto func = [remoteAddr, transport, strategy]() {
274 BluetoothRemoteDevice remoteDevice(remoteAddr, transport);
275 A2dpSource *profile = A2dpSource::GetProfile();
276 int32_t err = profile->SetConnectStrategy(remoteDevice, strategy);
277 HILOGI("err: %{public}d", err);
278 return NapiAsyncWorkRet(err);
279 };
280 auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
281 NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
282 asyncWork->Run();
283 return asyncWork->GetRet();
284 }
285
GetConnectionStrategy(napi_env env,napi_callback_info info)286 napi_value NapiA2dpSource::GetConnectionStrategy(napi_env env, napi_callback_info info)
287 {
288 HILOGI("start");
289 std::string remoteAddr{};
290 auto status = CheckDeviceAddressParam(env, info, remoteAddr);
291 NAPI_BT_ASSERT_RETURN_UNDEF(env, status == napi_ok, BT_ERR_INVALID_PARAM);
292
293 int transport = BT_TRANSPORT_BREDR;
294 auto func = [remoteAddr, transport]() {
295 int strategy = 0;
296 BluetoothRemoteDevice remoteDevice(remoteAddr, transport);
297 A2dpSource *profile = A2dpSource::GetProfile();
298 int32_t err = profile->GetConnectStrategy(remoteDevice, strategy);
299 HILOGI("err: %{public}d, deviceName: %{public}d", err, strategy);
300 auto object = std::make_shared<NapiNativeInt>(strategy);
301 return NapiAsyncWorkRet(err, object);
302 };
303 auto asyncWork = NapiAsyncWorkFactory::CreateAsyncWork(env, info, func, ASYNC_WORK_NO_NEED_CALLBACK);
304 NAPI_BT_ASSERT_RETURN_UNDEF(env, asyncWork, BT_ERR_INTERNAL_ERROR);
305 asyncWork->Run();
306 return asyncWork->GetRet();
307 }
308
GetConnectionState(napi_env env,napi_callback_info info)309 napi_value NapiA2dpSource::GetConnectionState(napi_env env, napi_callback_info info)
310 {
311 return GetDeviceState(env, info);
312 }
getConnectedDevices(napi_env env,napi_callback_info info)313 napi_value NapiA2dpSource::getConnectedDevices(napi_env env, napi_callback_info info)
314 {
315 return GetConnectionDevices(env, info);
316 }
317
318 #endif
319 } // namespace Bluetooth
320 } // namespace OHOS