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