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