1 /*
2 * Copyright (c) 2023-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 "NapiAudioSessionMgr"
17 #endif
18
19 #include "napi_audio_error.h"
20 #include "napi_param_utils.h"
21 #include "napi_audio_enum.h"
22 #include "audio_errors.h"
23 #include "napi_audio_session_callback.h"
24 #include "napi_audio_session_manager.h"
25
26 namespace OHOS {
27 namespace AudioStandard {
28 using namespace std;
29 using namespace HiviewDFX;
30 static __thread napi_ref g_sessionMgrConstructor = nullptr;
31
32 const std::string AUDIO_SESSION_MGR_NAPI_CLASS_NAME = "AudioSessionManager";
33
NapiAudioSessionMgr()34 NapiAudioSessionMgr::NapiAudioSessionMgr()
35 : env_(nullptr), audioSessionMngr_(nullptr) {}
36
37 NapiAudioSessionMgr::~NapiAudioSessionMgr() = default;
38
Destructor(napi_env env,void * nativeObject,void * finalizeHint)39 void NapiAudioSessionMgr::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
40 {
41 if (nativeObject == nullptr) {
42 AUDIO_WARNING_LOG("Native object is null");
43 return;
44 }
45 auto obj = static_cast<NapiAudioSessionMgr *>(nativeObject);
46 ObjectRefMap<NapiAudioSessionMgr>::DecreaseRef(obj);
47 AUDIO_INFO_LOG("Decrease obj count");
48 }
49
Construct(napi_env env,napi_callback_info info)50 napi_value NapiAudioSessionMgr::Construct(napi_env env, napi_callback_info info)
51 {
52 AUDIO_DEBUG_LOG("Construct");
53 napi_status status;
54 napi_value result = nullptr;
55 NapiParamUtils::GetUndefinedValue(env);
56
57 size_t argc = ARGS_TWO;
58 napi_value argv[ARGS_TWO] = {0};
59 napi_value thisVar = nullptr;
60 void *data = nullptr;
61 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
62 unique_ptr<NapiAudioSessionMgr> napiSessionMgr = make_unique<NapiAudioSessionMgr>();
63 CHECK_AND_RETURN_RET_LOG(napiSessionMgr != nullptr, result, "No memory");
64
65 napiSessionMgr->env_ = env;
66 napiSessionMgr->audioSessionMngr_ = AudioSessionManager::GetInstance();
67 ObjectRefMap<NapiAudioSessionMgr>::Insert(napiSessionMgr.get());
68
69 status = napi_wrap(env, thisVar, static_cast<void*>(napiSessionMgr.get()),
70 NapiAudioSessionMgr::Destructor, nullptr, nullptr);
71 if (status != napi_ok) {
72 ObjectRefMap<NapiAudioSessionMgr>::Erase(napiSessionMgr.get());
73 return result;
74 }
75 napiSessionMgr.release();
76 return thisVar;
77 }
78
Init(napi_env env,napi_value exports)79 napi_value NapiAudioSessionMgr::Init(napi_env env, napi_value exports)
80 {
81 napi_status status;
82 napi_value constructor;
83 napi_value result = nullptr;
84 const int32_t refCount = ARGS_ONE;
85 napi_get_undefined(env, &result);
86
87 napi_property_descriptor audio_session_mgr_properties[] = {
88 DECLARE_NAPI_FUNCTION("on", On),
89 DECLARE_NAPI_FUNCTION("off", Off),
90 DECLARE_NAPI_FUNCTION("activateAudioSession", ActivateAudioSession),
91 DECLARE_NAPI_FUNCTION("deactivateAudioSession", DeactivateAudioSession),
92 DECLARE_NAPI_FUNCTION("isAudioSessionActivated", IsAudioSessionActivated),
93 };
94
95 status = napi_define_class(env, AUDIO_SESSION_MGR_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct, nullptr,
96 sizeof(audio_session_mgr_properties) / sizeof(audio_session_mgr_properties[PARAM0]),
97 audio_session_mgr_properties, &constructor);
98 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_define_class fail");
99
100 status = napi_create_reference(env, constructor, refCount, &g_sessionMgrConstructor);
101 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_create_reference fail");
102 status = napi_set_named_property(env, exports, AUDIO_SESSION_MGR_NAPI_CLASS_NAME.c_str(), constructor);
103 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_set_named_property fail");
104 return exports;
105 }
106
CreateSessionManagerWrapper(napi_env env)107 napi_value NapiAudioSessionMgr::CreateSessionManagerWrapper(napi_env env)
108 {
109 napi_status status;
110 napi_value result = nullptr;
111 napi_value constructor;
112
113 status = napi_get_reference_value(env, g_sessionMgrConstructor, &constructor);
114 if (status != napi_ok) {
115 AUDIO_ERR_LOG("Failed in CreateSessionManagerWrapper, %{public}d", status);
116 goto fail;
117 }
118 status = napi_new_instance(env, constructor, PARAM0, nullptr, &result);
119 if (status != napi_ok) {
120 AUDIO_ERR_LOG("napi_new_instance failed, status:%{public}d", status);
121 goto fail;
122 }
123 return result;
124
125 fail:
126 napi_get_undefined(env, &result);
127 return result;
128 }
129
CheckContextStatus(std::shared_ptr<AudioSessionMgrAsyncContext> context)130 bool NapiAudioSessionMgr::CheckContextStatus(std::shared_ptr<AudioSessionMgrAsyncContext> context)
131 {
132 CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context object is nullptr.");
133 if (context->native == nullptr) {
134 context->SignError(NAPI_ERR_SYSTEM);
135 return false;
136 }
137 return true;
138 }
139
ActivateAudioSession(napi_env env,napi_callback_info info)140 napi_value NapiAudioSessionMgr::ActivateAudioSession(napi_env env, napi_callback_info info)
141 {
142 auto context = std::make_shared<AudioSessionMgrAsyncContext>();
143 if (context == nullptr) {
144 AUDIO_ERR_LOG("ActivateAudioSession failed : no memory");
145 NapiAudioError::ThrowError(env, "ActivateAudioSession failed : no memory", NAPI_ERR_NO_MEMORY);
146 return NapiParamUtils::GetUndefinedValue(env);
147 }
148
149 auto inputParser = [env, context](size_t argc, napi_value *argv) {
150 NAPI_CHECK_ARGS_RETURN_VOID(context, argc >= ARGS_ONE, "invalid arguments",
151 NAPI_ERR_INPUT_INVALID);
152 context->status = NapiParamUtils::GetAudioSessionStrategy(env, context->audioSessionStrategy, argv[PARAM0]);
153 NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok, "getAudioSessionStrategy failed",
154 NAPI_ERR_INVALID_PARAM);
155 };
156 context->GetCbInfo(env, info, inputParser);
157
158 if ((context->status != napi_ok) && (context->errCode == NAPI_ERR_INPUT_INVALID)) {
159 NapiAudioError::ThrowError(env, context->errCode, context->errMessage);
160 return NapiParamUtils::GetUndefinedValue(env);
161 }
162
163 auto executor = [context]() {
164 CHECK_AND_RETURN_LOG(CheckContextStatus(context), "context object state is error.");
165 auto obj = reinterpret_cast<NapiAudioSessionMgr*>(context->native);
166 ObjectRefMap objectGuard(obj);
167 auto *napiSessionMgr = objectGuard.GetPtr();
168 if (napiSessionMgr == nullptr || napiSessionMgr->audioSessionMngr_ == nullptr) {
169 context->SignError(NAPI_ERR_SYSTEM);
170 AUDIO_ERR_LOG("The napiSessionMgr or audioSessionMngr is nullptr");
171 return;
172 }
173 context->intValue = napiSessionMgr->audioSessionMngr_->ActivateAudioSession(context->audioSessionStrategy);
174 if (context->intValue != SUCCESS) {
175 context->SignError(NAPI_ERR_SYSTEM);
176 }
177 };
178
179 auto complete = [env, context](napi_value &output) {
180 NapiParamUtils::SetValueInt32(env, context->intValue, output);
181 };
182 return NapiAsyncWork::Enqueue(env, context, "ActivateAudioSession", executor, complete);
183 }
184
DeactivateAudioSession(napi_env env,napi_callback_info info)185 napi_value NapiAudioSessionMgr::DeactivateAudioSession(napi_env env, napi_callback_info info)
186 {
187 auto context = std::make_shared<AudioSessionMgrAsyncContext>();
188 if (context == nullptr) {
189 AUDIO_ERR_LOG("DeactivateAudioSession failed : no memory");
190 NapiAudioError::ThrowError(env, "DeactivateAudioSession failed : no memory",
191 NAPI_ERR_NO_MEMORY);
192 return NapiParamUtils::GetUndefinedValue(env);
193 }
194 context->GetCbInfo(env, info);
195
196 auto executor = [context]() {
197 CHECK_AND_RETURN_LOG(CheckContextStatus(context), "context object state is error.");
198 auto obj = reinterpret_cast<NapiAudioSessionMgr*>(context->native);
199 ObjectRefMap objectGuard(obj);
200 auto *napiSessionMgr = objectGuard.GetPtr();
201 if (napiSessionMgr == nullptr || napiSessionMgr->audioSessionMngr_ == nullptr) {
202 context->SignError(NAPI_ERR_SYSTEM);
203 AUDIO_ERR_LOG("The napiSessionMgr or audioSessionMngr is nullptr");
204 return;
205 }
206 context->intValue = napiSessionMgr->audioSessionMngr_->DeactivateAudioSession();
207 if (context->intValue != SUCCESS) {
208 context->SignError(NAPI_ERR_SYSTEM);
209 }
210 };
211
212 auto complete = [env, context](napi_value &output) {
213 NapiParamUtils::SetValueInt32(env, context->intValue, output);
214 };
215 return NapiAsyncWork::Enqueue(env, context, "DeactivateAudioSession", executor, complete);
216 }
217
IsAudioSessionActivated(napi_env env,napi_callback_info info)218 napi_value NapiAudioSessionMgr::IsAudioSessionActivated(napi_env env, napi_callback_info info)
219 {
220 napi_value result = nullptr;
221 auto context = std::make_shared<AudioSessionMgrAsyncContext>();
222 if (context == nullptr) {
223 AUDIO_ERR_LOG("IsAudioSessionActivated failed : no memory");
224 NapiAudioError::ThrowError(env, "IsAudioSessionActivated failed : no memory",
225 NAPI_ERR_NO_MEMORY);
226 return NapiParamUtils::GetUndefinedValue(env);
227 }
228 context->GetCbInfo(env, info);
229
230 CHECK_AND_RETURN_RET_LOG(CheckContextStatus(context), result, "context object state is error.");
231 auto obj = reinterpret_cast<NapiAudioSessionMgr*>(context->native);
232 ObjectRefMap objectGuard(obj);
233 auto *napiSessionMgr = objectGuard.GetPtr();
234 if (napiSessionMgr == nullptr || napiSessionMgr->audioSessionMngr_ == nullptr) {
235 AUDIO_ERR_LOG("The napiSessionMgr or audioSessionMngr is nullptr");
236 return nullptr;
237 }
238 context->isActive = napiSessionMgr->audioSessionMngr_->IsAudioSessionActivated();
239 NapiParamUtils::SetValueBoolean(env, context->isActive, result);
240 return result;
241 }
242
RegisterCallback(napi_env env,napi_value jsThis,napi_value * args,const std::string & cbName)243 void NapiAudioSessionMgr::RegisterCallback(napi_env env, napi_value jsThis,
244 napi_value *args, const std::string &cbName)
245 {
246 if (!cbName.compare(AUDIOSESSION_CALLBACK_NAME)) {
247 NapiAudioSessionMgr *napiSessionMgr = nullptr;
248 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&napiSessionMgr));
249 CHECK_AND_RETURN_LOG((status == napi_ok) && (napiSessionMgr != nullptr) &&
250 (napiSessionMgr->audioSessionMngr_ != nullptr), "Failed to retrieve session mgr napi instance.");
251 RegisterAudioSessionCallback(env, args, cbName, napiSessionMgr);
252 } else {
253 AUDIO_ERR_LOG("NapiAudioSessionMgr::No such callback supported");
254 NapiAudioError::ThrowError(env, NAPI_ERR_INVALID_PARAM,
255 "parameter verification failed: The param of type is not supported");
256 }
257 }
258
RegisterAudioSessionCallback(napi_env env,napi_value * args,const std::string & cbName,NapiAudioSessionMgr * napiSessionMgr)259 void NapiAudioSessionMgr::RegisterAudioSessionCallback(napi_env env, napi_value *args,
260 const std::string &cbName, NapiAudioSessionMgr *napiSessionMgr)
261 {
262 if (!napiSessionMgr->audioSessionCallbackNapi_) {
263 napiSessionMgr->audioSessionCallbackNapi_ = std::make_shared<NapiAudioSessionCallback>(env);
264 CHECK_AND_RETURN_LOG(napiSessionMgr->audioSessionCallbackNapi_ != nullptr,
265 "NapiAudioSessionMgr: Memory Allocation Failed !!");
266
267 int32_t ret =
268 napiSessionMgr->audioSessionMngr_->SetAudioSessionCallback(napiSessionMgr->audioSessionCallbackNapi_);
269 CHECK_AND_RETURN_LOG(ret == SUCCESS, "Registering of AudioSessionDeactiveEvent Callback Failed");
270 }
271
272 std::shared_ptr<NapiAudioSessionCallback> cb =
273 std::static_pointer_cast<NapiAudioSessionCallback>(napiSessionMgr->audioSessionCallbackNapi_);
274 cb->SaveCallbackReference(args[PARAM1]);
275 if (!cb->GetAudioSessionTsfnFlag()) {
276 cb->CreateAudioSessionTsfn(env);
277 }
278
279 AUDIO_INFO_LOG("OnRendererStateChangeCallback is successful");
280 }
281
On(napi_env env,napi_callback_info info)282 napi_value NapiAudioSessionMgr::On(napi_env env, napi_callback_info info)
283 {
284 const size_t requireArgc = ARGS_TWO;
285 size_t argc = ARGS_THREE;
286
287 napi_value undefinedResult = nullptr;
288 napi_get_undefined(env, &undefinedResult);
289
290 napi_value args[requireArgc + PARAM1] = {nullptr, nullptr, nullptr};
291 napi_value jsThis = nullptr;
292 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
293 CHECK_AND_RETURN_RET_LOG(status == napi_ok && argc == requireArgc, NapiAudioError::ThrowErrorAndReturn(env,
294 NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified"),
295 "status for arguments error");
296
297 napi_valuetype eventType = napi_undefined;
298 napi_typeof(env, args[PARAM0], &eventType);
299 CHECK_AND_RETURN_RET_LOG(eventType == napi_string, NapiAudioError::ThrowErrorAndReturn(env,
300 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of eventType must be string"),
301 "eventType error");
302 std::string callbackName = NapiParamUtils::GetStringArgument(env, args[PARAM0]);
303 AUDIO_DEBUG_LOG("AudioStreamMgrNapi: On callbackName: %{public}s", callbackName.c_str());
304
305 napi_valuetype handler = napi_undefined;
306 napi_typeof(env, args[PARAM1], &handler);
307 CHECK_AND_RETURN_RET_LOG(
308 handler == napi_function, NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID,
309 "incorrect parameter types: The type of handler must be function"), "handler is invalid");
310 RegisterCallback(env, jsThis, args, callbackName);
311 return undefinedResult;
312 }
313
UnregisterCallback(napi_env env,napi_value jsThis)314 void NapiAudioSessionMgr::UnregisterCallback(napi_env env, napi_value jsThis)
315 {
316 AUDIO_INFO_LOG("UnregisterCallback");
317 NapiAudioSessionMgr *napiSessionMgr = nullptr;
318 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&napiSessionMgr));
319 CHECK_AND_RETURN_LOG((status == napi_ok) && (napiSessionMgr != nullptr) &&
320 (napiSessionMgr->audioSessionMngr_ != nullptr), "Failed to retrieve session mgr instance.");
321
322 int32_t ret = napiSessionMgr->audioSessionMngr_->UnsetAudioSessionCallback();
323 if (ret) {
324 AUDIO_ERR_LOG("Unset AudioSessionCallback Failed");
325 return;
326 }
327 if (napiSessionMgr->audioSessionCallbackNapi_ != nullptr) {
328 napiSessionMgr->audioSessionCallbackNapi_.reset();
329 napiSessionMgr->audioSessionCallbackNapi_ = nullptr;
330 }
331 AUDIO_ERR_LOG("Unset AudioSessionCallback Success");
332 }
333
UnregisterCallbackCarryParam(napi_env env,napi_value jsThis,napi_value * args,size_t len)334 void NapiAudioSessionMgr::UnregisterCallbackCarryParam(napi_env env, napi_value jsThis, napi_value *args, size_t len)
335 {
336 AUDIO_INFO_LOG("UnregisterCallback");
337 NapiAudioSessionMgr *napiSessionMgr = nullptr;
338 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&napiSessionMgr));
339 CHECK_AND_RETURN_LOG((status == napi_ok) && (napiSessionMgr != nullptr) &&
340 (napiSessionMgr->audioSessionMngr_ != nullptr), "Failed to retrieve session mgr instance.");
341 if (!napiSessionMgr->audioSessionCallbackNapi_) {
342 napiSessionMgr->audioSessionCallbackNapi_ = std::make_shared<NapiAudioSessionCallback>(env);
343 CHECK_AND_RETURN_LOG(napiSessionMgr->audioSessionCallbackNapi_ != nullptr,
344 "Memory Allocation Failed !!");
345 int32_t ret =
346 napiSessionMgr->audioSessionMngr_->UnsetAudioSessionCallback(napiSessionMgr->audioSessionCallbackNapi_);
347 CHECK_AND_RETURN_LOG(ret == SUCCESS, "Unregister Callback CarryParam Failed");
348 }
349 std::shared_ptr<NapiAudioSessionCallback> cb =
350 std::static_pointer_cast<NapiAudioSessionCallback>(napiSessionMgr->audioSessionCallbackNapi_);
351 cb->SaveCallbackReference(args[PARAM0]);
352 AUDIO_ERR_LOG("Unset AudioSessionCallback Success");
353 }
354
Off(napi_env env,napi_callback_info info)355 napi_value NapiAudioSessionMgr::Off(napi_env env, napi_callback_info info)
356 {
357 const size_t requireArgc = ARGS_ONE;
358 size_t argc = PARAM2;
359
360 napi_value undefinedResult = nullptr;
361 napi_get_undefined(env, &undefinedResult);
362
363 napi_value args[requireArgc + PARAM1] = {nullptr, nullptr};
364 napi_value jsThis = nullptr;
365 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
366 if (status != napi_ok || argc < requireArgc) {
367 AUDIO_ERR_LOG("Off fail to napi_get_cb_info/Requires min 1 parameters");
368 NapiAudioError::ThrowError(env, NAPI_ERR_INPUT_INVALID,
369 "mandatory parameters are left unspecified");
370 return undefinedResult;
371 }
372
373 napi_valuetype eventType = napi_undefined;
374 napi_typeof(env, args[PARAM0], &eventType);
375 CHECK_AND_RETURN_RET_LOG(eventType == napi_string, NapiAudioError::ThrowErrorAndReturn(env,
376 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of eventType must be string"),
377 "event error");
378 std::string callbackName = NapiParamUtils::GetStringArgument(env, args[PARAM0]);
379 if (!callbackName.compare(AUDIOSESSION_CALLBACK_NAME)) {
380 napi_valuetype handler = napi_undefined;
381 napi_typeof(env, args[PARAM1], &handler);
382 if (handler == napi_function) {
383 UnregisterCallbackCarryParam(env, jsThis, args, sizeof(args));
384 } else {
385 UnregisterCallback(env, jsThis);
386 }
387 } else {
388 AUDIO_ERR_LOG("NapiAudioSessionMgr::No such callback supported");
389 NapiAudioError::ThrowError(env, NAPI_ERR_INVALID_PARAM,
390 "parameter verification failed: The param of type is not supported");
391 }
392 return undefinedResult;
393 }
394 } // namespace AudioStandard
395 } // namespace OHOS
396