• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "NapiAudioCollaborativeManager"
17 #endif
18 
19 #include "napi_audio_collaborative_manager.h"
20 
21 #include <vector>
22 #include "napi_audio_error.h"
23 #include "napi_param_utils.h"
24 #include "napi_audio_enum.h"
25 #include "audio_errors.h"
26 #include "audio_manager_log.h"
27 
28 namespace OHOS {
29 namespace AudioStandard {
30 using namespace std;
31 using namespace HiviewDFX;
32 static __thread napi_ref g_collaborativeManagerConstructor = nullptr;
NapiAudioCollaborativeManager()33 NapiAudioCollaborativeManager::NapiAudioCollaborativeManager()
34     : audioCollaborativeMngr_(nullptr), env_(nullptr) {}
35 NapiAudioCollaborativeManager::~NapiAudioCollaborativeManager() = default;
36 
CheckContextStatus(std::shared_ptr<AudioCollaborativeManagerAsyncContext> context)37 bool NapiAudioCollaborativeManager::CheckContextStatus(std::shared_ptr<AudioCollaborativeManagerAsyncContext> context)
38 {
39     CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context object is nullptr.");
40     if (context->native == nullptr) {
41         context->SignError(NAPI_ERR_SYSTEM);
42         AUDIO_ERR_LOG("context object state is error.");
43         return false;
44     }
45     return true;
46 }
47 
CheckAudioCollaborativeManagerStatus(NapiAudioCollaborativeManager * napi,std::shared_ptr<AudioCollaborativeManagerAsyncContext> context)48 bool NapiAudioCollaborativeManager::CheckAudioCollaborativeManagerStatus(NapiAudioCollaborativeManager *napi,
49     std::shared_ptr<AudioCollaborativeManagerAsyncContext> context)
50 {
51     CHECK_AND_RETURN_RET_LOG(napi != nullptr, false, "napi object is nullptr.");
52     if (napi->audioCollaborativeMngr_ == nullptr) {
53         context->SignError(NAPI_ERR_SYSTEM);
54         AUDIO_ERR_LOG("audioCollaborativeMngr is nullptr.");
55         return false;
56     }
57     return true;
58 }
59 
Destructor(napi_env env,void * nativeObject,void * finalizeHint)60 void NapiAudioCollaborativeManager::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
61 {
62     CHECK_AND_RETURN_LOG(nativeObject, "Native object is null");
63     auto obj = static_cast<NapiAudioCollaborativeManager *>(nativeObject);
64     ObjectRefMap<NapiAudioCollaborativeManager>::DecreaseRef(obj);
65     AUDIO_INFO_LOG("Decrease obj count");
66 }
67 
Construct(napi_env env,napi_callback_info info)68 napi_value NapiAudioCollaborativeManager::Construct(napi_env env, napi_callback_info info)
69 {
70     AUDIO_INFO_LOG("Construct");
71     napi_status status;
72     napi_value result = nullptr;
73     napi_get_undefined(env, &result);
74 
75     size_t argc = ARGS_TWO;
76     napi_value argv[ARGS_TWO] = {0};
77     napi_value thisVar = nullptr;
78     void *data = nullptr;
79     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
80     unique_ptr<NapiAudioCollaborativeManager> napiAudioCollaborativeManager =
81         make_unique<NapiAudioCollaborativeManager>();
82     CHECK_AND_RETURN_RET_LOG(napiAudioCollaborativeManager != nullptr, result, "No memory");
83 
84     napiAudioCollaborativeManager->audioCollaborativeMngr_ = AudioCollaborativeManager::GetInstance();
85     napiAudioCollaborativeManager->env_ = env;
86 
87     ObjectRefMap<NapiAudioCollaborativeManager>::Insert(napiAudioCollaborativeManager.get());
88     status = napi_wrap(env, thisVar, static_cast<void*>(napiAudioCollaborativeManager.get()),
89         NapiAudioCollaborativeManager::Destructor, nullptr, nullptr);
90     if (status != napi_ok) {
91         ObjectRefMap<NapiAudioCollaborativeManager>::Erase(napiAudioCollaborativeManager.get());
92         return result;
93     }
94     napiAudioCollaborativeManager.release();
95     return thisVar;
96 }
97 
GetParamWithSync(const napi_env & env,napi_callback_info info,size_t & argc,napi_value * args)98 NapiAudioCollaborativeManager* NapiAudioCollaborativeManager::GetParamWithSync(const napi_env &env,
99     napi_callback_info info, size_t &argc, napi_value *args)
100 {
101     napi_status status;
102     NapiAudioCollaborativeManager *napiAudioCollaborativeManager = nullptr;
103     napi_value jsThis = nullptr;
104 
105     status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
106     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr,
107         "GetParamWithSync fail to napi_get_cb_info");
108 
109     status = napi_unwrap(env, jsThis, (void **)&napiAudioCollaborativeManager);
110     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "napi_unwrap failed");
111     CHECK_AND_RETURN_RET_LOG(napiAudioCollaborativeManager != nullptr &&
112         napiAudioCollaborativeManager->audioCollaborativeMngr_ !=
113         nullptr, napiAudioCollaborativeManager, "GetParamWithSync fail to napi_unwrap");
114     return napiAudioCollaborativeManager;
115 }
116 
CreateCollaborativeManagerWrapper(napi_env env)117 napi_value NapiAudioCollaborativeManager::CreateCollaborativeManagerWrapper(napi_env env)
118 {
119     napi_status status;
120     napi_value result = nullptr;
121     napi_value constructor;
122 
123     auto HandleNapiError = [env](const char *logMsg, napi_status status, napi_value &result) {
124         AUDIO_INFO_LOG("%s, status %{public}d", logMsg, status);
125         napi_get_undefined(env, &result);
126         return result;
127     };
128     status = napi_get_reference_value(env, g_collaborativeManagerConstructor, &constructor);
129     CHECK_AND_RETURN_RET(status == napi_ok,
130         HandleNapiError("napi_get_reference_value fail!", status, result));
131 
132     status = napi_new_instance(env, constructor, 0, nullptr, &result);
133     CHECK_AND_RETURN_RET(status == napi_ok,
134         HandleNapiError("napi_new_instance fail!", status, result));
135 
136     return result;
137 }
138 
Init(napi_env env,napi_value exports)139 napi_value NapiAudioCollaborativeManager::Init(napi_env env, napi_value exports)
140 {
141     AUDIO_DEBUG_LOG("Init");
142 
143     napi_status status;
144     napi_value constructor;
145     napi_value result = nullptr;
146     const int32_t refCount = 1;
147     napi_get_undefined(env, &result);
148 
149     napi_property_descriptor audio_collaborative_manager_properties[] = {
150         DECLARE_NAPI_FUNCTION("isCollaborativePlaybackSupported", IsCollaborativePlaybackSupported),
151         DECLARE_NAPI_FUNCTION("isCollaborativePlaybackEnabledForDevice", IsCollaborativePlaybackEnabledForDevice),
152         DECLARE_NAPI_FUNCTION("setCollaborativePlaybackEnabledForDevice", SetCollaborativePlaybackEnabledForDevice),
153     };
154 
155     status = napi_define_class(env, AUDIO_COLLABORATIVE_MANAGER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct,
156         nullptr,
157         sizeof(audio_collaborative_manager_properties) / sizeof(audio_collaborative_manager_properties[PARAM0]),
158         audio_collaborative_manager_properties, &constructor);
159     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_define_class fail");
160 
161     status = napi_create_reference(env, constructor, refCount, &g_collaborativeManagerConstructor);
162     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_create_reference fail");
163     status = napi_set_named_property(env, exports, AUDIO_COLLABORATIVE_MANAGER_NAPI_CLASS_NAME.c_str(),
164         constructor);
165     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_set_named_property fail");
166     return exports;
167 }
168 
IsCollaborativePlaybackSupported(napi_env env,napi_callback_info info)169 napi_value NapiAudioCollaborativeManager::IsCollaborativePlaybackSupported(napi_env env, napi_callback_info info)
170 {
171     AUDIO_DEBUG_LOG("in");
172     CHECK_AND_RETURN_RET_LOG(PermissionUtil::VerifySelfPermission(),
173         NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_PERMISSION_DENIED), "No system permission");
174 
175     napi_value result = nullptr;
176     size_t argc = PARAM0;
177     auto *napiAudioCollaborativeManager = GetParamWithSync(env, info, argc, nullptr);
178     CHECK_AND_RETURN_RET_LOG(argc == PARAM0, NapiAudioError::ThrowErrorAndReturn(env,
179         NAPI_ERR_INPUT_INVALID), "invalid arguments");
180     CHECK_AND_RETURN_RET_LOG(napiAudioCollaborativeManager != nullptr, result,
181         "napiAudioCollaborativeManager is nullptr");
182     CHECK_AND_RETURN_RET_LOG(napiAudioCollaborativeManager->audioCollaborativeMngr_ != nullptr, result,
183         "audioCollaborativeMngr_ is nullptr");
184     bool isCollaborativeSupported =
185         napiAudioCollaborativeManager->audioCollaborativeMngr_->IsCollaborativePlaybackSupported();
186     NapiParamUtils::SetValueBoolean(env, isCollaborativeSupported, result);
187     return result;
188 }
189 
IsCollaborativePlaybackEnabledForDevice(napi_env env,napi_callback_info info)190 napi_value NapiAudioCollaborativeManager::IsCollaborativePlaybackEnabledForDevice(
191     napi_env env, napi_callback_info info)
192 {
193     AUDIO_INFO_LOG("in");
194     napi_value result = nullptr;
195     CHECK_AND_RETURN_RET_LOG(PermissionUtil::VerifySelfPermission(),
196         NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_PERMISSION_DENIED), "No system permission");
197 
198     bool isCollaborativeEnabled = false;
199     const size_t requireArgc = ARGS_ONE;
200     size_t argc = PARAM1;
201     napi_value args[ARGS_ONE] = {};
202     auto *napiAudioCollaborativeManager = GetParamWithSync(env, info, argc, args);
203     CHECK_AND_RETURN_RET_LOG(napiAudioCollaborativeManager != nullptr, result,
204         "napiAudioCollaborativeManager is nullptr");
205     CHECK_AND_RETURN_RET_LOG(napiAudioCollaborativeManager->audioCollaborativeMngr_ != nullptr, result,
206         "audioCollaborativeMngr is nullptr");
207 
208     if (argc == requireArgc) {
209         bool argTransFlag = true;
210         napi_valuetype valueType = napi_undefined;
211         napi_typeof(env, args[PARAM0], &valueType);
212         CHECK_AND_RETURN_RET_LOG(valueType == napi_object, NapiAudioError::ThrowErrorAndReturn(env,
213             NAPI_ERR_INPUT_INVALID,
214             "incorrect parameter types: The type of deviceDescriptor must be object"), "invalid valueType");
215 
216         std::shared_ptr<AudioDeviceDescriptor> selectedAudioDevice = std::make_shared<AudioDeviceDescriptor>();
217         NapiParamUtils::GetAudioDeviceDescriptor(env, selectedAudioDevice, argTransFlag, args[PARAM0]);
218         CHECK_AND_RETURN_RET_LOG(argTransFlag == true, NapiAudioError::ThrowErrorAndReturn(env,
219             NAPI_ERR_INPUT_INVALID,
220             "parameter verification failed: The param of deviceDescriptor must be interface AudioDeviceDescriptor"),
221             "invalid parameter");
222         if ((selectedAudioDevice->deviceType_ != DEVICE_TYPE_BLUETOOTH_A2DP) ||
223             (selectedAudioDevice->connectState_ != CONNECTED)) {
224             NapiAudioError::ThrowError(env, NAPI_ERR_INVALID_PARAM,
225                 "invalid arguments, device is not A2DP or device is connected");
226             return NapiParamUtils::GetUndefinedValue(env);
227         }
228 
229         isCollaborativeEnabled = napiAudioCollaborativeManager->audioCollaborativeMngr_
230             ->IsCollaborativePlaybackEnabledForDevice(selectedAudioDevice);
231     } else {
232         NapiAudioError::ThrowError(env, NAPI_ERR_INPUT_INVALID, "invalid arguments");
233         return NapiParamUtils::GetUndefinedValue(env);
234     }
235     NapiParamUtils::SetValueBoolean(env, isCollaborativeEnabled, result);
236     return result;
237 }
238 
SetCollaborativePlaybackEnabledForDevice(napi_env env,napi_callback_info info)239 napi_value NapiAudioCollaborativeManager::SetCollaborativePlaybackEnabledForDevice(
240     napi_env env, napi_callback_info info)
241 {
242     CHECK_AND_RETURN_RET_LOG(PermissionUtil::VerifySelfPermission(),
243         NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_PERMISSION_DENIED), "No system permission.");
244 
245     auto context = std::make_shared<AudioCollaborativeManagerAsyncContext>();
246     if (context == nullptr) {
247         AUDIO_ERR_LOG("SetCollaborativePlaybackEnabledForDevice failed : no memory");
248         NapiAudioError::ThrowError(env, "SetCollaborativePlaybackEnabledForDevice failed : no memory",
249             NAPI_ERR_NO_MEMORY);
250         return NapiParamUtils::GetUndefinedValue(env);
251     }
252 
253     auto inputParser = [env, context](size_t argc, napi_value *argv) {
254         NAPI_CHECK_ARGS_RETURN_VOID(context, argc == ARGS_TWO, "mandatory parameters are left unspecified",
255             NAPI_ERR_INPUT_INVALID);
256 
257         napi_valuetype valueType = napi_undefined;
258         napi_typeof(env, argv[PARAM0], &valueType);
259         NAPI_CHECK_ARGS_RETURN_VOID(context, valueType == napi_object,
260             "incorrect parameter types: The type of deviceDescriptor must be object", NAPI_ERR_INPUT_INVALID);
261 
262         bool argTransFlag = true;
263         context->status = NapiParamUtils::GetAudioDeviceDescriptor(env, context->deviceDescriptor, argTransFlag,
264             argv[PARAM0]);
265         NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok,
266             "incorrect parameter types: The param of deviceDescriptor must be interface AudioDeviceDescriptor",
267             NAPI_ERR_INPUT_INVALID);
268 
269         context->status = NapiParamUtils::GetValueBoolean(env, context->collaborativeEnable, argv[PARAM1]);
270         NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok,
271             "incorrect parameter types: The type of enable must be boolean",
272             NAPI_ERR_INPUT_INVALID);
273     };
274 
275     context->GetCbInfo(env, info, inputParser);
276     if (context->status != napi_ok) {
277         NapiAudioError::ThrowError(env, context->errCode, context->errMessage);
278         return NapiParamUtils::GetUndefinedValue(env);
279     }
280 
281     return UpdateCollaborativeEnabled(env, context);
282 }
283 
UpdateCollaborativeEnabled(napi_env env,std::shared_ptr<AudioCollaborativeManagerAsyncContext> & context)284 napi_value NapiAudioCollaborativeManager::UpdateCollaborativeEnabled(napi_env env,
285     std::shared_ptr<AudioCollaborativeManagerAsyncContext> &context)
286 {
287     auto executor = [context]() {
288         CHECK_AND_RETURN_LOG(CheckContextStatus(context), "context object state is error.");
289         auto obj = reinterpret_cast<NapiAudioCollaborativeManager*>(context->native);
290         ObjectRefMap objectGuard(obj);
291         auto *napiAudioCollaborativeManager = objectGuard.GetPtr();
292         CHECK_AND_RETURN_LOG(CheckAudioCollaborativeManagerStatus(napiAudioCollaborativeManager, context),
293             "audio collaborative manager state is error.");
294 
295         if (!napiAudioCollaborativeManager->audioCollaborativeMngr_->IsCollaborativePlaybackSupported()) {
296             context->SignError(NAPI_ERR_UNAVAILABLE_ON_DEVICE);
297             return;
298         }
299         if ((context->deviceDescriptor->deviceType_ != DEVICE_TYPE_BLUETOOTH_A2DP) ||
300             (context->deviceDescriptor->connectState_ != CONNECTED)) {
301             context->SignError(NAPI_ERR_INVALID_PARAM);
302             return;
303         }
304         context->intValue =
305             napiAudioCollaborativeManager->audioCollaborativeMngr_->SetCollaborativePlaybackEnabledForDevice(
306                 context->deviceDescriptor, context->collaborativeEnable);
307 
308         if (context->intValue == ERR_PERMISSION_DENIED) {
309             context->SignError(NAPI_ERR_NO_PERMISSION);
310         } else if (context->intValue != SUCCESS) {
311             context->SignError(NAPI_ERR_SYSTEM);
312         }
313     };
314 
315     auto complete = [env](napi_value &output) {
316         output = NapiParamUtils::GetUndefinedValue(env);
317     };
318     return NapiAsyncWork::Enqueue(env, context, "SetCollaborativeEnabled", executor, complete);
319 }
320 
321 }
322 }