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