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 "NapiTonePlayer"
17 #endif
18
19 #include "napi_toneplayer.h"
20
21 #include "napi_param_utils.h"
22 #include "napi_audio_error.h"
23
24 using namespace std;
25
26 namespace OHOS {
27 namespace AudioStandard {
28 static __thread napi_ref g_tonePlayerConstructor = nullptr;
29 std::unique_ptr<AudioRendererInfo> NapiTonePlayer::sRendererInfo_ = nullptr;
30 mutex NapiTonePlayer::createMutex_;
31 int32_t NapiTonePlayer::isConstructSuccess_ = SUCCESS;
32
ThrowErrorAndReturn(napi_env env,int32_t errCode)33 static napi_value ThrowErrorAndReturn(napi_env env, int32_t errCode)
34 {
35 NapiAudioError::ThrowError(env, errCode);
36 return nullptr;
37 }
38
NapiTonePlayer()39 NapiTonePlayer::NapiTonePlayer()
40 : tonePlayer_(nullptr), env_(nullptr) {}
41
42 NapiTonePlayer::~NapiTonePlayer() = default;
43
CheckTonePlayerStatus(NapiTonePlayer * napi,std::shared_ptr<TonePlayerAsyncContext> context)44 bool NapiTonePlayer::CheckTonePlayerStatus(NapiTonePlayer *napi,
45 std::shared_ptr<TonePlayerAsyncContext> context)
46 {
47 CHECK_AND_RETURN_RET_LOG(napi != nullptr, false, "napi object is nullptr.");
48 if (napi->tonePlayer_ == nullptr) {
49 context->SignError(NAPI_ERR_SYSTEM);
50 return false;
51 }
52 return true;
53 }
54
Destructor(napi_env env,void * nativeObject,void * finalizeHint)55 void NapiTonePlayer::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
56 {
57 if (nativeObject == nullptr) {
58 AUDIO_WARNING_LOG("Native object is null");
59 return;
60 }
61 auto obj = static_cast<NapiTonePlayer *>(nativeObject);
62 ObjectRefMap<NapiTonePlayer>::DecreaseRef(obj);
63 AUDIO_INFO_LOG("Decrease obj count");
64 }
65
Init(napi_env env,napi_value exports)66 napi_value NapiTonePlayer::Init(napi_env env, napi_value exports)
67 {
68 napi_status status;
69 napi_value constructor;
70 napi_value result = nullptr;
71 const int32_t refCount = 1;
72 napi_get_undefined(env, &result);
73 AUDIO_DEBUG_LOG("NapiTonePlayer::Init");
74 napi_property_descriptor audio_toneplayer_properties[] = {
75 DECLARE_NAPI_FUNCTION("load", Load),
76 DECLARE_NAPI_FUNCTION("start", Start),
77 DECLARE_NAPI_FUNCTION("stop", Stop),
78 DECLARE_NAPI_FUNCTION("release", Release),
79 };
80
81 napi_property_descriptor static_prop[] = {
82 DECLARE_NAPI_STATIC_FUNCTION("createTonePlayer", CreateTonePlayer),
83 DECLARE_NAPI_STATIC_FUNCTION("createTonePlayerSync", CreateTonePlayerSync),
84 };
85
86 status = napi_define_class(env, NAPI_TONE_PLAYER_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct, nullptr,
87 sizeof(audio_toneplayer_properties) / sizeof(audio_toneplayer_properties[PARAM0]),
88 audio_toneplayer_properties, &constructor);
89 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_define_class failed");
90
91 status = napi_create_reference(env, constructor, refCount, &g_tonePlayerConstructor);
92 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_create_reference failed");
93
94 status = napi_set_named_property(env, exports, NAPI_TONE_PLAYER_CLASS_NAME.c_str(), constructor);
95 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_set_named_property failed");
96
97 status = napi_define_properties(env, exports,
98 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop);
99 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_define_properties failed");
100
101 return exports;
102 }
103
Construct(napi_env env,napi_callback_info info)104 napi_value NapiTonePlayer::Construct(napi_env env, napi_callback_info info)
105 {
106 napi_status status;
107 napi_value result = nullptr;
108 napi_get_undefined(env, &result);
109
110 size_t argCount = ARGS_TWO;
111 napi_value thisVar = nullptr;
112 status = napi_get_cb_info(env, info, &argCount, nullptr, &thisVar, nullptr);
113 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
114
115 unique_ptr<NapiTonePlayer> napiTonePlayer = make_unique<NapiTonePlayer>();
116 CHECK_AND_RETURN_RET_LOG(napiTonePlayer != nullptr, result, "No memory");
117 ObjectRefMap<NapiTonePlayer>::Insert(napiTonePlayer.get());
118
119 napiTonePlayer->env_ = env;
120 AudioRendererInfo rendererInfo = {};
121 CHECK_AND_RETURN_RET_LOG(sRendererInfo_ != nullptr, result, "Construct sRendererInfo_ is null");
122 rendererInfo = *sRendererInfo_;
123 std::string cacheDir = "/data/storage/el2/base/cache";
124 /* NapiTonePlayer not support other rendererFlags, only support flag 0 */
125 if (rendererInfo.rendererFlags != 0) {
126 rendererInfo.rendererFlags = 0;
127 }
128 napiTonePlayer->tonePlayer_ = TonePlayer::Create(cacheDir, rendererInfo);
129
130 if (napiTonePlayer->tonePlayer_ == nullptr) {
131 AUDIO_ERR_LOG("Toneplayer Create failed");
132 NapiTonePlayer::isConstructSuccess_ = NAPI_ERR_PERMISSION_DENIED;
133 }
134
135 status = napi_wrap(env, thisVar, static_cast<void*>(napiTonePlayer.get()),
136 NapiTonePlayer::Destructor, nullptr, nullptr);
137 if (status != napi_ok) {
138 ObjectRefMap<NapiTonePlayer>::Erase(napiTonePlayer.get());
139 return result;
140 }
141 napiTonePlayer.release();
142 return thisVar;
143 }
144
CreateTonePlayerWrapper(napi_env env,unique_ptr<AudioRendererInfo> & rendererInfo)145 napi_value NapiTonePlayer::CreateTonePlayerWrapper(napi_env env, unique_ptr<AudioRendererInfo> &rendererInfo)
146 {
147 lock_guard<mutex> lock(createMutex_);
148 napi_status status = napi_invalid_arg;
149 napi_value result = nullptr;
150 napi_value constructor;
151
152 if (rendererInfo == nullptr) {
153 goto fail;
154 }
155 status = napi_get_reference_value(env, g_tonePlayerConstructor, &constructor);
156 if (status != napi_ok) {
157 goto fail;
158 }
159 sRendererInfo_ = move(rendererInfo);
160 status = napi_new_instance(env, constructor, 0, nullptr, &result);
161 sRendererInfo_.release();
162 if (status != napi_ok) {
163 goto fail;
164 }
165 return result;
166
167 fail:
168 AUDIO_ERR_LOG("Failed in CreateTonePlayerWrapper, %{public}d", status);
169 napi_get_undefined(env, &result);
170 return result;
171 }
172
CreateTonePlayer(napi_env env,napi_callback_info info)173 napi_value NapiTonePlayer::CreateTonePlayer(napi_env env, napi_callback_info info)
174 {
175 AUDIO_INFO_LOG("CreateTonePlayer");
176 auto context = std::make_shared<TonePlayerAsyncContext>();
177 if (context == nullptr) {
178 AUDIO_ERR_LOG("CreateTonePlayer failed : no memory");
179 NapiAudioError::ThrowError(env, "CreateTonePlayer failed : no memory", NAPI_ERR_NO_MEMORY);
180 return NapiParamUtils::GetUndefinedValue(env);
181 }
182
183 auto inputParser = [env, context](size_t argc, napi_value *argv) {
184 NAPI_CHECK_ARGS_RETURN_VOID(context, argc >= ARGS_ONE, "invalid arguments",
185 NAPI_ERR_INVALID_PARAM);
186 context->status = NapiParamUtils::GetRendererInfo(env, &context->rendererInfo, argv[PARAM0]);
187 NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok, "GetRendererInfo failed",
188 NAPI_ERR_INVALID_PARAM);
189 };
190 context->GetCbInfo(env, info, inputParser);
191
192 auto complete = [env, context](napi_value &output) {
193 unique_ptr<AudioRendererInfo> audioRendererInfo = make_unique<AudioRendererInfo>();
194 *audioRendererInfo = context->rendererInfo;
195 output = CreateTonePlayerWrapper(env, audioRendererInfo);
196 };
197
198 return NapiAsyncWork::Enqueue(env, context, "CreateTonePlayer", nullptr, complete);
199 }
200
CreateTonePlayerSync(napi_env env,napi_callback_info info)201 napi_value NapiTonePlayer::CreateTonePlayerSync(napi_env env, napi_callback_info info)
202 {
203 size_t argc = ARGS_ONE;
204 napi_value argv[ARGS_ONE] = {};
205 napi_status status = NapiParamUtils::GetParam(env, info, argc, argv);
206 CHECK_AND_RETURN_RET_LOG((argc == ARGS_ONE) && (status == napi_ok),
207 ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID), "GetParam failed");
208
209 napi_valuetype valueType = napi_undefined;
210 napi_typeof(env, argv[PARAM0], &valueType);
211 CHECK_AND_RETURN_RET_LOG(valueType == napi_object,
212 ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID), "valueType invaild");
213
214 AudioRendererInfo rendererInfo;
215
216 CHECK_AND_RETURN_RET_LOG(NapiParamUtils::GetRendererInfo(env, &rendererInfo, argv[PARAM0]) == napi_ok,
217 ThrowErrorAndReturn(env, NAPI_ERR_INVALID_PARAM), "GetRendererInfo failed");
218
219 unique_ptr<AudioRendererInfo> audioRendererInfo = make_unique<AudioRendererInfo>();
220 CHECK_AND_RETURN_RET_LOG(audioRendererInfo != nullptr,
221 ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY), "audioRendererInfo create failed,no memery.");
222 *audioRendererInfo = rendererInfo;
223
224 return NapiTonePlayer::CreateTonePlayerWrapper(env, audioRendererInfo);
225 }
226
Load(napi_env env,napi_callback_info info)227 napi_value NapiTonePlayer::Load(napi_env env, napi_callback_info info)
228 {
229 auto context = std::make_shared<TonePlayerAsyncContext>();
230 if (context == nullptr) {
231 AUDIO_ERR_LOG("Load failed : no memory");
232 NapiAudioError::ThrowError(env, "Load failed : no memory", NAPI_ERR_NO_MEMORY);
233 return NapiParamUtils::GetUndefinedValue(env);
234 }
235
236 auto inputParser = [env, context](size_t argc, napi_value *argv) {
237 NAPI_CHECK_ARGS_RETURN_VOID(context, argc >= ARGS_ONE, "invalid arguments",
238 NAPI_ERR_INVALID_PARAM);
239 context->status = NapiParamUtils::GetValueInt32(env, context->toneType, argv[PARAM0]);
240 NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok, "get toneType failed",
241 NAPI_ERR_INVALID_PARAM);
242 NAPI_CHECK_ARGS_RETURN_VOID(context, ToneTypeCheck(env, context->toneType), "toneType invaild",
243 NAPI_ERR_INVALID_PARAM);
244 };
245 context->GetCbInfo(env, info, inputParser);
246
247 auto executor = [context]() {
248 auto obj = reinterpret_cast<NapiTonePlayer*>(context->native);
249 ObjectRefMap objectGuard(obj);
250 auto *napiTonePlayer = objectGuard.GetPtr();
251 ToneType toneType = static_cast<ToneType>(context->toneType);
252 CHECK_AND_RETURN_LOG(CheckTonePlayerStatus(napiTonePlayer, context),
253 "context object state is error.");
254 context->isTrue = napiTonePlayer->tonePlayer_->LoadTone(toneType);
255 if (!context->isTrue) {
256 context->SignError(NAPI_ERR_SYSTEM);
257 }
258 };
259 auto complete = [env](napi_value &output) {
260 output = NapiParamUtils::GetUndefinedValue(env);
261 };
262 return NapiAsyncWork::Enqueue(env, context, "Load", executor, complete);
263 }
264
Start(napi_env env,napi_callback_info info)265 napi_value NapiTonePlayer::Start(napi_env env, napi_callback_info info)
266 {
267 auto context = std::make_shared<TonePlayerAsyncContext>();
268 if (context == nullptr) {
269 AUDIO_ERR_LOG("Start failed : no memory");
270 NapiAudioError::ThrowError(env, "Start failed : no memory", NAPI_ERR_NO_MEMORY);
271 return NapiParamUtils::GetUndefinedValue(env);
272 }
273
274 context->GetCbInfo(env, info);
275
276 auto executor = [context]() {
277 auto obj = reinterpret_cast<NapiTonePlayer*>(context->native);
278 ObjectRefMap objectGuard(obj);
279 auto *napiTonePlayer = objectGuard.GetPtr();
280 CHECK_AND_RETURN_LOG(CheckTonePlayerStatus(napiTonePlayer, context),
281 "context object state is error.");
282 context->isTrue = napiTonePlayer->tonePlayer_->StartTone();
283 if (!context->isTrue) {
284 context->SignError(NAPI_ERR_SYSTEM);
285 }
286 };
287 auto complete = [env](napi_value &output) {
288 output = NapiParamUtils::GetUndefinedValue(env);
289 };
290 return NapiAsyncWork::Enqueue(env, context, "Start", executor, complete);
291 }
292
Stop(napi_env env,napi_callback_info info)293 napi_value NapiTonePlayer::Stop(napi_env env, napi_callback_info info)
294 {
295 auto context = std::make_shared<TonePlayerAsyncContext>();
296 if (context == nullptr) {
297 AUDIO_ERR_LOG("Stop failed : no memory");
298 NapiAudioError::ThrowError(env, "Stop failed : no memory", NAPI_ERR_NO_MEMORY);
299 return NapiParamUtils::GetUndefinedValue(env);
300 }
301
302 context->GetCbInfo(env, info);
303
304 auto executor = [context]() {
305 auto obj = reinterpret_cast<NapiTonePlayer*>(context->native);
306 ObjectRefMap objectGuard(obj);
307 auto *napiTonePlayer = objectGuard.GetPtr();
308 CHECK_AND_RETURN_LOG(CheckTonePlayerStatus(napiTonePlayer, context),
309 "context object state is error.");
310 context->isTrue = napiTonePlayer->tonePlayer_->StopTone();
311 if (!context->isTrue) {
312 context->SignError(NAPI_ERR_SYSTEM);
313 }
314 };
315 auto complete = [env](napi_value &output) {
316 output = NapiParamUtils::GetUndefinedValue(env);
317 };
318 return NapiAsyncWork::Enqueue(env, context, "Stop", executor, complete);
319 }
320
Release(napi_env env,napi_callback_info info)321 napi_value NapiTonePlayer::Release(napi_env env, napi_callback_info info)
322 {
323 auto context = std::make_shared<TonePlayerAsyncContext>();
324 if (context == nullptr) {
325 AUDIO_ERR_LOG("Release failed : no memory");
326 NapiAudioError::ThrowError(env, "Release failed : no memory", NAPI_ERR_NO_MEMORY);
327 return NapiParamUtils::GetUndefinedValue(env);
328 }
329
330 context->GetCbInfo(env, info);
331
332 auto executor = [context]() {
333 auto obj = reinterpret_cast<NapiTonePlayer*>(context->native);
334 ObjectRefMap objectGuard(obj);
335 auto *napiTonePlayer = objectGuard.GetPtr();
336 CHECK_AND_RETURN_LOG(CheckTonePlayerStatus(napiTonePlayer, context),
337 "context object state is error.");
338 context->isTrue = napiTonePlayer->tonePlayer_->Release();
339 if (!context->isTrue) {
340 context->SignError(NAPI_ERR_SYSTEM);
341 }
342 };
343 auto complete = [env](napi_value &output) {
344 output = NapiParamUtils::GetUndefinedValue(env);
345 };
346 return NapiAsyncWork::Enqueue(env, context, "Release", executor, complete);
347 }
348
ToneTypeCheck(napi_env env,int32_t type)349 bool NapiTonePlayer::ToneTypeCheck(napi_env env, int32_t type)
350 {
351 int32_t len = sizeof(TONE_TYPE_ARR) / sizeof(TONE_TYPE_ARR[PARAM0]);
352 for (int32_t i = 0; i < len; i++) {
353 if (TONE_TYPE_ARR[i] == type) {
354 return true;
355 }
356 }
357 return false;
358 }
359 } // namespace AudioStandard
360 } // namespace OHOS