• 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 "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