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 
16 #include "system_tone_player_napi.h"
17 
18 #include "system_sound_log.h"
19 #include "common_napi.h"
20 
21 namespace {
22 /* Constants for array index */
23 const int32_t PARAM0 = 0;
24 const int32_t PARAM1 = 1;
25 
26 /* Constants for array size */
27 const int32_t ARGS_ONE = 1;
28 const int32_t ARGS_TWO = 2;
29 
30 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "SystemTonePlayerNapi"};
31 }
32 
33 namespace OHOS {
34 namespace Media {
35 thread_local napi_ref SystemTonePlayerNapi::sConstructor_ = nullptr;
36 std::shared_ptr<SystemTonePlayer> SystemTonePlayerNapi::sSystemTonePlayer_ = nullptr;
37 
SystemTonePlayerNapi()38 SystemTonePlayerNapi::SystemTonePlayerNapi() : env_(nullptr) {}
39 
40 SystemTonePlayerNapi::~SystemTonePlayerNapi() = default;
41 
Init(napi_env env,napi_value exports)42 napi_value SystemTonePlayerNapi::Init(napi_env env, napi_value exports)
43 {
44     napi_status status;
45     napi_value ctorObj;
46     int32_t refCount = 1;
47 
48     napi_property_descriptor system_tone_player_prop[] = {
49         DECLARE_NAPI_FUNCTION("getTitle", GetTitle),
50         DECLARE_NAPI_FUNCTION("prepare", Prepare),
51         DECLARE_NAPI_FUNCTION("start", Start),
52         DECLARE_NAPI_FUNCTION("stop", Stop),
53         DECLARE_NAPI_FUNCTION("release", Release),
54         DECLARE_NAPI_FUNCTION("setAudioVolumeScale", SetAudioVolumeScale),
55         DECLARE_NAPI_FUNCTION("getAudioVolumeScale", GetAudioVolumeScale),
56         DECLARE_NAPI_FUNCTION("getSupportedHapticsFeatures", GetSupportedHapticsFeatures),
57         DECLARE_NAPI_FUNCTION("setHapticsFeature", SetHapticsFeature),
58         DECLARE_NAPI_FUNCTION("getHapticsFeature", GetHapticsFeature),
59     };
60 
61     status = napi_define_class(env, SYSTEM_TONE_PLAYER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
62         SystemTonePlayerNapiConstructor, nullptr, sizeof(system_tone_player_prop) / sizeof(system_tone_player_prop[0]),
63         system_tone_player_prop, &ctorObj);
64     if (status == napi_ok) {
65         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
66             status = napi_set_named_property(env, exports, SYSTEM_TONE_PLAYER_NAPI_CLASS_NAME.c_str(), ctorObj);
67             if (status == napi_ok) {
68                 return exports;
69             }
70         }
71     }
72 
73     return nullptr;
74 }
75 
SystemTonePlayerNapiConstructor(napi_env env,napi_callback_info info)76 napi_value SystemTonePlayerNapi::SystemTonePlayerNapiConstructor(napi_env env, napi_callback_info info)
77 {
78     napi_status status;
79     napi_value result = nullptr;
80     napi_value thisVar = nullptr;
81 
82     napi_get_undefined(env, &result);
83     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
84     if (status == napi_ok && thisVar != nullptr) {
85         std::unique_ptr<SystemTonePlayerNapi> obj = std::make_unique<SystemTonePlayerNapi>();
86         if (obj != nullptr) {
87             ObjectRefMap<SystemTonePlayerNapi>::Insert(obj.get());
88             obj->env_ = env;
89             if (obj->sSystemTonePlayer_ != nullptr) {
90                 obj->systemTonePlayer_ = move(obj->sSystemTonePlayer_);
91             } else {
92                 MEDIA_LOGE("Failed to create sSystemTonePlayer_ instance.");
93                 return result;
94             }
95 
96             status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
97                 SystemTonePlayerNapi::SystemTonePlayerNapiDestructor, nullptr, nullptr);
98             if (status == napi_ok) {
99                 obj.release();
100                 return thisVar;
101             } else {
102                 ObjectRefMap<SystemTonePlayerNapi>::Erase(obj.get());
103                 MEDIA_LOGE("Failed to wrap the native system tone player object with JS.");
104             }
105         }
106     }
107 
108     return result;
109 }
110 
SystemTonePlayerNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)111 void SystemTonePlayerNapi::SystemTonePlayerNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
112 {
113     SystemTonePlayerNapi *systemTonePlayerHelper = reinterpret_cast<SystemTonePlayerNapi*>(nativeObject);
114     if (systemTonePlayerHelper != nullptr) {
115         ObjectRefMap<SystemTonePlayerNapi>::DecreaseRef(systemTonePlayerHelper);
116     }
117 }
118 
GetSystemTonePlayerInstance(napi_env env,std::shared_ptr<SystemTonePlayer> & systemTonePlayer)119 napi_value SystemTonePlayerNapi::GetSystemTonePlayerInstance(napi_env env,
120     std::shared_ptr<SystemTonePlayer> &systemTonePlayer)
121 {
122     napi_status status;
123     napi_value result = nullptr;
124     napi_value ctor;
125 
126     status = napi_get_reference_value(env, sConstructor_, &ctor);
127     if (status == napi_ok) {
128         sSystemTonePlayer_ = systemTonePlayer;
129         status = napi_new_instance(env, ctor, 0, nullptr, &result);
130         if (status == napi_ok) {
131             return result;
132         } else {
133             MEDIA_LOGE("GetSystemTonePlayerInstance: New instance could not be obtained.");
134         }
135     }
136 
137     napi_get_undefined(env, &result);
138     return result;
139 }
140 
CommonAsyncCallbackComplete(napi_env env,napi_status status,void * data)141 void SystemTonePlayerNapi::CommonAsyncCallbackComplete(napi_env env, napi_status status, void* data)
142 {
143     auto context = static_cast<SystemTonePlayerAsyncContext *>(data);
144     napi_value callback = nullptr;
145     napi_value retVal = nullptr;
146     napi_value result[2] = {};
147 
148     napi_get_undefined(env, &result[PARAM1]);
149     if (!context->status) {
150         napi_get_undefined(env, &result[PARAM0]);
151     } else {
152         napi_value message = nullptr;
153         napi_create_string_utf8(env, "Error: Operation is not supported or failed", NAPI_AUTO_LENGTH, &message);
154         napi_create_error(env, nullptr, message, &result[PARAM0]);
155     }
156 
157     if (context->deferred) {
158         if (!context->status) {
159             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
160         } else {
161             napi_reject_deferred(env, context->deferred, result[PARAM0]);
162         }
163     } else {
164         napi_get_reference_value(env, context->callbackRef, &callback);
165         napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
166         napi_delete_reference(env, context->callbackRef);
167     }
168     napi_delete_async_work(env, context->work);
169 
170     delete context;
171     context = nullptr;
172 }
173 
GetTitleAsyncCallbackComplete(napi_env env,napi_status status,void * data)174 void SystemTonePlayerNapi::GetTitleAsyncCallbackComplete(napi_env env, napi_status status, void *data)
175 {
176     auto context = static_cast<SystemTonePlayerAsyncContext *>(data);
177     napi_value getTitleCallback = nullptr;
178     napi_value retVal = nullptr;
179     napi_value result[2] = {};
180 
181     if (!context->status) {
182         napi_get_undefined(env, &result[PARAM0]);
183         napi_create_string_utf8(env, context->title.c_str(), NAPI_AUTO_LENGTH, &result[PARAM1]);
184     } else {
185         napi_value message = nullptr;
186         napi_create_string_utf8(env, "GetTitle Error: Operation is not supported or failed",
187             NAPI_AUTO_LENGTH, &message);
188         napi_create_error(env, nullptr, message, &result[PARAM0]);
189         napi_get_undefined(env, &result[PARAM1]);
190     }
191 
192     if (context->deferred) {
193         if (!context->status) {
194             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
195         } else {
196             napi_reject_deferred(env, context->deferred, result[PARAM0]);
197         }
198     } else {
199         napi_get_reference_value(env, context->callbackRef, &getTitleCallback);
200         napi_call_function(env, nullptr, getTitleCallback, ARGS_TWO, result, &retVal);
201         napi_delete_reference(env, context->callbackRef);
202     }
203     napi_delete_async_work(env, context->work);
204 
205     delete context;
206     context = nullptr;
207 }
208 
GetTitle(napi_env env,napi_callback_info info)209 napi_value SystemTonePlayerNapi::GetTitle(napi_env env, napi_callback_info info)
210 {
211     napi_value result = nullptr;
212     napi_value resource = nullptr;
213     size_t argc = ARGS_ONE;
214     napi_value argv[ARGS_ONE] = {0};
215     napi_value thisVar = nullptr;
216     const int32_t refCount = 1;
217 
218     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
219     napi_get_undefined(env, &result);
220     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "GetTitle: napi_get_cb_info failed");
221 
222     NAPI_ASSERT(env, argc <= ARGS_ONE, "GetTitle: requires 1 parameter maximum");
223     std::unique_ptr<SystemTonePlayerAsyncContext> asyncContext = std::make_unique<SystemTonePlayerAsyncContext>();
224     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
225     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
226         if (argc == ARGS_ONE) {
227             napi_valuetype valueType = napi_undefined;
228             napi_typeof(env, argv[PARAM0], &valueType);
229             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
230                 "GetTitle: the param type is not napi_function");
231             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
232         } else {
233             napi_create_promise(env, &asyncContext->deferred, &result);
234         }
235 
236         napi_create_string_utf8(env, "GetTitle", NAPI_AUTO_LENGTH, &resource);
237         status = napi_create_async_work(env, nullptr, resource,
238             [](napi_env env, void *data) {
239                 SystemTonePlayerAsyncContext *context = static_cast<SystemTonePlayerAsyncContext *>(data);
240                 auto obj = reinterpret_cast<SystemTonePlayerNapi*>(context->objectInfo);
241                 ObjectRefMap objectGuard(obj);
242                 auto *napiSystemTonePlayer = objectGuard.GetPtr();
243                 if (napiSystemTonePlayer == nullptr || napiSystemTonePlayer->systemTonePlayer_ == nullptr) {
244                     MEDIA_LOGE("The system tone player is nullptr!");
245                     context->status = MSERR_INVALID_STATE;
246                     return;
247                 }
248                 context->title = napiSystemTonePlayer->systemTonePlayer_->GetTitle();
249                 context->status = MSERR_OK;
250             },
251             GetTitleAsyncCallbackComplete, static_cast<void *>(asyncContext.get()), &asyncContext->work);
252         if (status != napi_ok) {
253             MEDIA_LOGE("GetTitle: Failed to get create async work");
254             napi_get_undefined(env, &result);
255         } else {
256             napi_queue_async_work(env, asyncContext->work);
257             asyncContext.release();
258         }
259     }
260 
261     return result;
262 }
263 
Prepare(napi_env env,napi_callback_info info)264 napi_value SystemTonePlayerNapi::Prepare(napi_env env, napi_callback_info info)
265 {
266     napi_status status;
267     napi_value result = nullptr;
268     napi_value resource = nullptr;
269     size_t argc = ARGS_ONE;
270     napi_value argv[ARGS_ONE] = {0};
271     napi_value thisVar = nullptr;
272     const int32_t refCount = 1;
273 
274     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
275     napi_get_undefined(env, &result);
276     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result,
277         "Prepare: Failed to retrieve details about the callback");
278 
279     NAPI_ASSERT(env, argc <= ARGS_ONE, "Prepare: requires 1 parameter maximum");
280     std::unique_ptr<SystemTonePlayerAsyncContext> asyncContext = std::make_unique<SystemTonePlayerAsyncContext>();
281     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
282     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
283         if (argc == ARGS_ONE) {
284             napi_valuetype valueType = napi_undefined;
285             napi_typeof(env, argv[PARAM0], &valueType);
286             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
287                 "Prepare: the param type is not napi_function");
288             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
289         } else {
290             napi_create_promise(env, &asyncContext->deferred, &result);
291         }
292 
293         napi_create_string_utf8(env, "Prepare", NAPI_AUTO_LENGTH, &resource);
294         status = napi_create_async_work(env, nullptr, resource,
295             [](napi_env env, void* data) {
296                 SystemTonePlayerAsyncContext *context = static_cast<SystemTonePlayerAsyncContext *>(data);
297                 auto obj = reinterpret_cast<SystemTonePlayerNapi *>(context->objectInfo);
298                 ObjectRefMap objectGuard(obj);
299                 auto *napiSystemTonePlayer = objectGuard.GetPtr();
300                 if (napiSystemTonePlayer == nullptr || napiSystemTonePlayer->systemTonePlayer_ == nullptr) {
301                     MEDIA_LOGE("The system tone player is nullptr!");
302                     context->status = MSERR_INVALID_STATE;
303                     return;
304                 }
305                 context->status = napiSystemTonePlayer->systemTonePlayer_->Prepare();
306             },
307             CommonAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
308         if (status != napi_ok) {
309             MEDIA_LOGE("Prepare: Failed to get create async work");
310             napi_get_undefined(env, &result);
311         } else {
312             napi_queue_async_work(env, asyncContext->work);
313             asyncContext.release();
314         }
315     }
316 
317     return result;
318 }
319 
StartAsyncCallbackComplete(napi_env env,napi_status status,void * data)320 void SystemTonePlayerNapi::StartAsyncCallbackComplete(napi_env env, napi_status status, void *data)
321 {
322     auto context = static_cast<SystemTonePlayerAsyncContext *>(data);
323     napi_value getTitleCallback = nullptr;
324     napi_value retVal = nullptr;
325     napi_value result[2] = {};
326 
327     if (!context->status) {
328         napi_get_undefined(env, &result[PARAM0]);
329         napi_create_int32(env, context->streamID, &result[PARAM1]);
330     } else {
331         napi_value message = nullptr;
332         napi_create_string_utf8(env, "GetTitle Error: Operation is not supported or failed",
333             NAPI_AUTO_LENGTH, &message);
334         napi_create_error(env, nullptr, message, &result[PARAM0]);
335         napi_get_undefined(env, &result[PARAM1]);
336     }
337 
338     if (context->deferred) {
339         if (!context->status) {
340             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
341         } else {
342             napi_reject_deferred(env, context->deferred, result[PARAM0]);
343         }
344     } else {
345         napi_get_reference_value(env, context->callbackRef, &getTitleCallback);
346         napi_call_function(env, nullptr, getTitleCallback, ARGS_TWO, result, &retVal);
347         napi_delete_reference(env, context->callbackRef);
348     }
349     napi_delete_async_work(env, context->work);
350 
351     delete context;
352     context = nullptr;
353 }
354 
Start(napi_env env,napi_callback_info info)355 napi_value SystemTonePlayerNapi::Start(napi_env env, napi_callback_info info)
356 {
357     napi_value result = nullptr;
358     napi_value resource = nullptr;
359     napi_value property = nullptr;
360     size_t argc = ARGS_ONE;
361     napi_value argv[ARGS_TWO] = {0};
362     napi_value thisVar = nullptr;
363     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
364     napi_get_undefined(env, &result);
365     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "Start: napi_get_cb_info failed");
366     NAPI_ASSERT(env, argc <= ARGS_TWO, "Start: requires 2 parameter maximum");
367 
368     std::unique_ptr<SystemTonePlayerAsyncContext> asyncContext = std::make_unique<SystemTonePlayerAsyncContext>();
369     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
370     CHECK_AND_RETURN_RET_LOG(status == napi_ok && asyncContext->objectInfo != nullptr, result,
371         "Start: napi_unwrap failed or objectInfo is nullptr.");
372 
373     if (argc == 0) {
374         napi_create_promise(env, &asyncContext->deferred, &result);
375     }
376     for (size_t i = PARAM0; i < argc; i++) {
377         napi_valuetype valueType = napi_undefined;
378         napi_typeof(env, argv[i], &valueType);
379         if (i == PARAM0 && valueType == napi_object) {
380             if (napi_get_named_property(env, argv[PARAM0], "muteAudio", &property) == napi_ok) {
381                 napi_get_value_bool(env, property, &(asyncContext->systemToneOptions.muteAudio));
382             }
383             if (napi_get_named_property(env, argv[PARAM0], "muteHaptics", &property) == napi_ok) {
384                 napi_get_value_bool(env, property, &(asyncContext->systemToneOptions.muteHaptics));
385             }
386             if (argc == ARGS_ONE) {
387                 napi_create_promise(env, &asyncContext->deferred, &result);
388             }
389         } else if ((i == PARAM0 || i == PARAM1) && valueType == napi_function) {
390             napi_create_reference(env, argv[PARAM0], 1, &asyncContext->callbackRef);
391         } else {
392             NAPI_ASSERT(env, false, "Start: type mismatch");
393         }
394     }
395 
396     napi_create_string_utf8(env, "Start", NAPI_AUTO_LENGTH, &resource);
397     status = napi_create_async_work(env, nullptr, resource, AsyncStart,
398         StartAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
399     if (status != napi_ok) {
400         napi_get_undefined(env, &result);
401     } else {
402         napi_queue_async_work(env, asyncContext->work);
403         asyncContext.release();
404     }
405     return result;
406 }
407 
AsyncStart(napi_env env,void * data)408 void SystemTonePlayerNapi::AsyncStart(napi_env env, void *data)
409 {
410     SystemTonePlayerAsyncContext *context = static_cast<SystemTonePlayerAsyncContext *>(data);
411     auto obj = reinterpret_cast<SystemTonePlayerNapi *>(context->objectInfo);
412     ObjectRefMap objectGuard(obj);
413     auto *napiSystemTonePlayer = objectGuard.GetPtr();
414     if (napiSystemTonePlayer == nullptr || napiSystemTonePlayer->systemTonePlayer_ == nullptr) {
415         MEDIA_LOGE("The system tone player is nullptr!");
416         context->status = MSERR_INVALID_STATE;
417         return;
418     }
419     context->streamID = napiSystemTonePlayer->systemTonePlayer_->Start(context->systemToneOptions);
420     context->status = MSERR_OK;
421 }
422 
Stop(napi_env env,napi_callback_info info)423 napi_value SystemTonePlayerNapi::Stop(napi_env env, napi_callback_info info)
424 {
425     napi_status status;
426     napi_value result = nullptr;
427     napi_value resource = nullptr;
428     size_t argc = ARGS_ONE;
429     napi_value argv[ARGS_TWO] = {0};
430     napi_value thisVar = nullptr;
431     const int32_t refCount = 1;
432 
433     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
434     napi_get_undefined(env, &result);
435     if (status != napi_ok || thisVar == nullptr) {
436         MEDIA_LOGE("Stop: Failed to retrieve details about the callback");
437         return result;
438     }
439 
440     NAPI_ASSERT(env, argc == ARGS_ONE || argc == ARGS_TWO, "Stop: requires 1 or 2 parameter");
441     std::unique_ptr<SystemTonePlayerAsyncContext> asyncContext = std::make_unique<SystemTonePlayerAsyncContext>();
442     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
443     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
444         napi_valuetype valueType = napi_undefined;
445         napi_typeof(env, argv[PARAM0], &valueType);
446         if (valueType == napi_number) {
447             napi_get_value_int32(env, argv[PARAM0], &(asyncContext->streamID));
448             napi_create_promise(env, &asyncContext->deferred, &result);
449         } else {
450             NAPI_ASSERT(env, false, "Stop: type mismatch");
451         }
452         if (argc == ARGS_TWO) {
453             napi_typeof(env, argv[PARAM1], &valueType);
454             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result, "Stop: the param type is not napi_function");
455             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
456         } else {
457             napi_create_promise(env, &asyncContext->deferred, &result);
458         }
459 
460         napi_create_string_utf8(env, "Stop", NAPI_AUTO_LENGTH, &resource);
461         status = napi_create_async_work(env, nullptr, resource, AsyncStop,
462             CommonAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
463         if (status != napi_ok) {
464             MEDIA_LOGE("Stop: Failed to get create async work");
465             napi_get_undefined(env, &result);
466         } else {
467             napi_queue_async_work(env, asyncContext->work);
468             asyncContext.release();
469         }
470     }
471 
472     return result;
473 }
474 
AsyncStop(napi_env env,void * data)475 void SystemTonePlayerNapi::AsyncStop(napi_env env, void *data)
476 {
477     SystemTonePlayerAsyncContext *context = static_cast<SystemTonePlayerAsyncContext *>(data);
478     auto obj = reinterpret_cast<SystemTonePlayerNapi *>(context->objectInfo);
479     ObjectRefMap objectGuard(obj);
480     auto *napiSystemTonePlayer = objectGuard.GetPtr();
481     if (napiSystemTonePlayer == nullptr || napiSystemTonePlayer->systemTonePlayer_ == nullptr) {
482         MEDIA_LOGE("The system tone player is nullptr!");
483         context->status = MSERR_INVALID_STATE;
484         return;
485     }
486     context->status = napiSystemTonePlayer->systemTonePlayer_->Stop(context->streamID);
487 }
488 
Release(napi_env env,napi_callback_info info)489 napi_value SystemTonePlayerNapi::Release(napi_env env, napi_callback_info info)
490 {
491     napi_status status;
492     napi_value result = nullptr;
493     napi_value resource = nullptr;
494     size_t argc = ARGS_ONE;
495     napi_value argv[ARGS_ONE] = {0};
496     napi_value thisVar = nullptr;
497     const int32_t refCount = 1;
498 
499     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
500     napi_get_undefined(env, &result);
501     if (status != napi_ok || thisVar == nullptr) {
502         MEDIA_LOGE("Release: Failed to retrieve details about the callback");
503         return result;
504     }
505 
506     NAPI_ASSERT(env, argc <= ARGS_ONE, "Release: requires 1 parameter maximum");
507     std::unique_ptr<SystemTonePlayerAsyncContext> asyncContext = std::make_unique<SystemTonePlayerAsyncContext>();
508     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
509     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
510         if (argc == ARGS_ONE) {
511             napi_valuetype valueType = napi_undefined;
512             napi_typeof(env, argv[PARAM0], &valueType);
513             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
514                 "Release: the param type is not napi_function");
515             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
516         } else {
517             napi_create_promise(env, &asyncContext->deferred, &result);
518         }
519 
520         napi_create_string_utf8(env, "Release", NAPI_AUTO_LENGTH, &resource);
521         status = napi_create_async_work(env, nullptr, resource, AsyncRelease,
522             CommonAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
523         if (status != napi_ok) {
524             MEDIA_LOGE("Release: Failed to get create async work");
525             napi_get_undefined(env, &result);
526         } else {
527             napi_queue_async_work(env, asyncContext->work);
528             asyncContext.release();
529         }
530     }
531 
532     return result;
533 }
534 
AsyncRelease(napi_env env,void * data)535 void SystemTonePlayerNapi::AsyncRelease(napi_env env, void *data)
536 {
537     SystemTonePlayerAsyncContext *context = static_cast<SystemTonePlayerAsyncContext *>(data);
538     auto obj = reinterpret_cast<SystemTonePlayerNapi *>(context->objectInfo);
539     ObjectRefMap objectGuard(obj);
540     auto *napiSystemTonePlayer = objectGuard.GetPtr();
541     if (napiSystemTonePlayer == nullptr || napiSystemTonePlayer->systemTonePlayer_ == nullptr) {
542         MEDIA_LOGE("The system tone player is nullptr!");
543         context->status = MSERR_INVALID_STATE;
544         return;
545     }
546     context->status = napiSystemTonePlayer->systemTonePlayer_->Release();
547 }
548 
SetAudioVolumeScale(napi_env env,napi_callback_info info)549 napi_value SystemTonePlayerNapi::SetAudioVolumeScale(napi_env env, napi_callback_info info)
550 {
551     napi_status status;
552     napi_value result = nullptr;
553     size_t argc = ARGS_ONE;
554     napi_value argv[ARGS_TWO] = {0};
555     napi_value thisVar = nullptr;
556 
557     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
558     napi_get_undefined(env, &result);
559     if (status != napi_ok || thisVar == nullptr) {
560         MEDIA_LOGE("SetAudioVolumeScale: Failed to retrieve details about the callback");
561         return result;
562     }
563 
564     NAPI_ASSERT(env, argc >= ARGS_ONE, "SetAudioVolumeScale: requires 1 parameter");
565     std::unique_ptr<SystemTonePlayerAsyncContext> asyncContext = std::make_unique<SystemTonePlayerAsyncContext>();
566     SystemTonePlayerNapi *objectInfo = nullptr;
567     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&objectInfo));
568     if (status == napi_ok && objectInfo != nullptr) {
569         napi_valuetype valueType = napi_undefined;
570         napi_typeof(env, argv[PARAM0], &valueType);
571         NAPI_ASSERT(env, valueType == napi_number, "SetAudioVolumeScale: type mismatch");
572         double value;
573         napi_get_value_double(env, argv[PARAM0], &value);
574         float volume  = static_cast<float>(value);
575         ObjectRefMap objectGuard(objectInfo);
576         auto *napiSystemTonePlayer = objectGuard.GetPtr();
577         int32_t ret = napiSystemTonePlayer->systemTonePlayer_->SetAudioVolume(volume);
578         if (ret != MSERR_OK) {
579             napi_throw_error(env, std::to_string(ret).c_str(),
580                 "SetAudioVolumeScale: Operation is not supported or failed");
581         }
582     }
583     return result;
584 }
585 
GetAudioVolumeScale(napi_env env,napi_callback_info info)586 napi_value SystemTonePlayerNapi::GetAudioVolumeScale(napi_env env, napi_callback_info info)
587 {
588     napi_value result = nullptr;
589     size_t argc = ARGS_ONE;
590     napi_value argv[ARGS_ONE] = {0};
591     napi_value thisVar = nullptr;
592 
593     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
594     napi_get_undefined(env, &result);
595     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result,
596         "GetAudioVolume: napi_get_cb_info failed");
597 
598     SystemTonePlayerNapi* objectInfo = nullptr;
599     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&objectInfo));
600     if (status == napi_ok && objectInfo != nullptr) {
601         ObjectRefMap objectGuard(objectInfo);
602         auto *napiSystemTonePlayer = objectGuard.GetPtr();
603         float volume;
604         int32_t ret = napiSystemTonePlayer->systemTonePlayer_->GetAudioVolume(volume);
605         if (ret != MSERR_OK) {
606             napi_throw_error(env, std::to_string(ret).c_str(),
607                 "SetAudioVolumeScale: Operation is not supported or failed");
608         } else {
609             napi_create_double(env, static_cast<double>(volume), &result);
610         }
611     }
612     return result;
613 }
614 
GetSupportHapticsFeaturesComplete(napi_env env,napi_status status,void * data)615 static void GetSupportHapticsFeaturesComplete(napi_env env, napi_status status, void *data)
616 {
617     auto context = static_cast<SystemTonePlayerAsyncContext *>(data);
618     napi_value result[2] = {};
619     napi_status curStatus;
620 
621     if (!context->status) {
622         napi_get_undefined(env, &result[PARAM0]);
623         napi_create_array_with_length(env, context->toneHapticsFeatures.size(), &result[PARAM1]);
624         napi_value value;
625         for (size_t i = 0; i < context->toneHapticsFeatures.size(); i++) {
626             value = nullptr;
627             curStatus = napi_create_int32(env, static_cast<int32_t>(context->toneHapticsFeatures[i]), &value);
628             if (curStatus != napi_ok || value == nullptr||
629                 napi_set_element(env, result[PARAM1], i, value) != napi_ok) {
630                 MEDIA_LOGE("GetSupportHapticsFeatures error : Failed to create number or add number to array");
631                 napi_value message = nullptr;
632                 napi_create_string_utf8(env,
633                     "GetSupportHapticsFeatures Error: Failed to create number or add number to array",
634                     NAPI_AUTO_LENGTH, &message);
635                 napi_create_error(env, nullptr, message, &result[PARAM0]);
636                 napi_get_undefined(env, &result[PARAM1]);
637                 context->status = MSERR_NO_MEMORY;
638                 break;
639             }
640         }
641     } else {
642         napi_value message = nullptr;
643         napi_create_string_utf8(env, "GetSupportHapticsFeatures Error: Operation is not supported or failed",
644             NAPI_AUTO_LENGTH, &message);
645         napi_create_error(env, nullptr, message, &result[PARAM0]);
646         napi_get_undefined(env, &result[PARAM1]);
647     }
648 
649     if (context->deferred) {
650         if (!context->status) {
651             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
652         } else {
653             napi_reject_deferred(env, context->deferred, result[PARAM0]);
654         }
655     }
656     napi_delete_async_work(env, context->work);
657 
658     delete context;
659     context = nullptr;
660 }
661 
GetSupportedHapticsFeatures(napi_env env,napi_callback_info info)662 napi_value SystemTonePlayerNapi::GetSupportedHapticsFeatures(napi_env env, napi_callback_info info)
663 {
664     napi_value result = nullptr;
665     napi_value resource = nullptr;
666     size_t argc = ARGS_ONE;
667     napi_value argv[ARGS_ONE] = {0};
668     napi_value thisVar = nullptr;
669 
670     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
671     napi_get_undefined(env, &result);
672     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result,
673         "GetSupportHapticsFeatures: napi_get_cb_info failed");
674 
675     std::unique_ptr<SystemTonePlayerAsyncContext> asyncContext = std::make_unique<SystemTonePlayerAsyncContext>();
676     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
677     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
678         napi_create_promise(env, &asyncContext->deferred, &result);
679         napi_create_string_utf8(env, "GetSupportHapticsFeatures", NAPI_AUTO_LENGTH, &resource);
680         status = napi_create_async_work(env, nullptr, resource,
681             [](napi_env env, void *data) {
682                 SystemTonePlayerAsyncContext *context = static_cast<SystemTonePlayerAsyncContext *>(data);
683                 auto obj = reinterpret_cast<SystemTonePlayerNapi*>(context->objectInfo);
684                 ObjectRefMap objectGuard(obj);
685                 auto *napiSystemTonePlayer = objectGuard.GetPtr();
686                 context->status = napiSystemTonePlayer->systemTonePlayer_->GetSupportHapticsFeatures(
687                     context->toneHapticsFeatures);
688             },
689             GetSupportHapticsFeaturesComplete, static_cast<void *>(asyncContext.get()), &asyncContext->work);
690         if (status != napi_ok) {
691             MEDIA_LOGE("GetSupportHapticsFeatures: Failed to get create async work");
692             napi_get_undefined(env, &result);
693         } else {
694             napi_queue_async_work(env, asyncContext->work);
695             asyncContext.release();
696         }
697     }
698     return result;
699 }
700 
SetHapticsFeature(napi_env env,napi_callback_info info)701 napi_value SystemTonePlayerNapi::SetHapticsFeature(napi_env env, napi_callback_info info)
702 {
703     napi_status status;
704     napi_value result = nullptr;
705     size_t argc = ARGS_ONE;
706     napi_value argv[ARGS_TWO] = {0};
707     napi_value thisVar = nullptr;
708 
709     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
710     napi_get_undefined(env, &result);
711     if (status != napi_ok || thisVar == nullptr) {
712         MEDIA_LOGE("SetHapticsFeature: Failed to retrieve details about the callback");
713         return result;
714     }
715 
716     NAPI_ASSERT(env, argc >= ARGS_ONE, "SetHapticsFeature: requires 1 parameter");
717     SystemTonePlayerNapi* objectInfo = nullptr;
718     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&objectInfo));
719     if (status == napi_ok && objectInfo != nullptr) {
720         napi_valuetype valueType = napi_undefined;
721         napi_typeof(env, argv[PARAM0], &valueType);
722         NAPI_ASSERT(env, valueType == napi_number, "SetHapticsFeature: type mismatch");
723         ToneHapticsFeature toneHapticsFeature;
724         napi_get_value_int32(env, argv[PARAM0], reinterpret_cast<int32_t*>(&toneHapticsFeature));
725         ObjectRefMap objectGuard(objectInfo);
726         auto *napiSystemTonePlayer = objectGuard.GetPtr();
727         int32_t ret = napiSystemTonePlayer->systemTonePlayer_->SetHapticsFeature(
728             toneHapticsFeature);
729         if (ret != MSERR_OK) {
730             napi_throw_error(env, std::to_string(ret).c_str(),
731                 "SetHapticsFeature: Operation is not supported or failed");
732         }
733     }
734     return result;
735 }
736 
GetHapticsFeature(napi_env env,napi_callback_info info)737 napi_value SystemTonePlayerNapi::GetHapticsFeature(napi_env env, napi_callback_info info)
738 {
739     napi_value result = nullptr;
740     size_t argc = ARGS_ONE;
741     napi_value argv[ARGS_ONE] = {0};
742     napi_value thisVar = nullptr;
743 
744     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
745     napi_get_undefined(env, &result);
746     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result,
747         "GetHapticsFeature: napi_get_cb_info failed");
748 
749     SystemTonePlayerNapi* objectInfo = nullptr;
750     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&objectInfo));
751     if (status == napi_ok && objectInfo != nullptr) {
752         ObjectRefMap objectGuard(objectInfo);
753         auto *napiSystemTonePlayer = objectGuard.GetPtr();
754         ToneHapticsFeature toneHapticsFeature;
755         int32_t ret = napiSystemTonePlayer->systemTonePlayer_->GetHapticsFeature(toneHapticsFeature);
756         if (ret != MSERR_OK) {
757             napi_throw_error(env, std::to_string(ret).c_str(),
758                 "GetHapticsFeature: Operation is not supported or failed");
759         } else {
760             napi_create_int32(env, static_cast<int32_t>(toneHapticsFeature), &result);
761         }
762     }
763     return result;
764 }
765 } // namespace Media
766 } // namespace OHOS