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