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