• 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 
16 #include "audio_haptic_player_napi.h"
17 
18 #include "audio_haptic_log.h"
19 
20 namespace {
21 
22 const std::string AUDIO_INTERRUPT_CALLBACK_NAME = "audioInterrupt";
23 const std::string END_OF_STREAM_CALLBACK_NAME = "endOfStream";
24 const double PRECISION = 100.00;
25 
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticPlayerNapi"};
27 }
28 
29 namespace OHOS {
30 namespace Media {
31 thread_local napi_ref AudioHapticPlayerNapi::sConstructor_ = nullptr;
32 std::shared_ptr<AudioHapticPlayer> AudioHapticPlayerNapi::sAudioHapticPlayer_ = nullptr;
33 
AudioHapticPlayerNapi()34 AudioHapticPlayerNapi::AudioHapticPlayerNapi() : env_(nullptr) {}
35 
36 AudioHapticPlayerNapi::~AudioHapticPlayerNapi() = default;
37 
Init(napi_env env,napi_value exports)38 napi_value AudioHapticPlayerNapi::Init(napi_env env, napi_value exports)
39 {
40     napi_status status;
41     napi_value ctorObj;
42     int32_t refCount = 1;
43 
44     napi_property_descriptor audioHapticPlayerProp[] = {
45         DECLARE_NAPI_FUNCTION("isMuted", IsMuted),
46         DECLARE_NAPI_FUNCTION("start", Start),
47         DECLARE_NAPI_FUNCTION("stop", Stop),
48         DECLARE_NAPI_FUNCTION("release", Release),
49         DECLARE_NAPI_FUNCTION("on", On),
50         DECLARE_NAPI_FUNCTION("off", Off),
51         DECLARE_NAPI_FUNCTION("setVolume", SetVolume),
52         DECLARE_NAPI_FUNCTION("setHapticsIntensity", SetHapticsIntensity),
53         DECLARE_NAPI_FUNCTION("enableHapticsInSilentMode", EnableHapticsInSilentMode),
54         DECLARE_NAPI_FUNCTION("isHapticsIntensityAdjustmentSupported", IsHapticsIntensityAdjustmentSupported),
55         DECLARE_NAPI_FUNCTION("setLoop", SetLoop),
56         DECLARE_NAPI_FUNCTION("setHapticsRamp", SetHapticsRamp),
57         DECLARE_NAPI_FUNCTION("isHapticsRampSupported", IsHapticsRampSupported),
58     };
59 
60     status = napi_define_class(env, AUDIO_HAPTIC_PLAYER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor,
61         nullptr, sizeof(audioHapticPlayerProp) / sizeof(audioHapticPlayerProp[0]), audioHapticPlayerProp, &ctorObj);
62     if (status == napi_ok) {
63         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
64             status = napi_set_named_property(env, exports, AUDIO_HAPTIC_PLAYER_NAPI_CLASS_NAME.c_str(), ctorObj);
65             if (status == napi_ok) {
66                 return exports;
67             }
68         }
69     }
70 
71     return nullptr;
72 }
73 
Constructor(napi_env env,napi_callback_info info)74 napi_value AudioHapticPlayerNapi::Constructor(napi_env env, napi_callback_info info)
75 {
76     napi_status status;
77     napi_value result = nullptr;
78     napi_value thisVar = nullptr;
79 
80     napi_get_undefined(env, &result);
81     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
82     if (status == napi_ok && thisVar != nullptr) {
83         std::unique_ptr<AudioHapticPlayerNapi> obj = std::make_unique<AudioHapticPlayerNapi>();
84         if (obj != nullptr) {
85             obj->env_ = env;
86             if (obj->sAudioHapticPlayer_ != nullptr) {
87                 obj->audioHapticPlayer_ = move(obj->sAudioHapticPlayer_);
88             } else {
89                 MEDIA_LOGE("Failed to create sAudioHapticPlayer_ instance.");
90                 return result;
91             }
92 
93             if (obj->audioHapticPlayer_ != nullptr && obj->callbackNapi_ == nullptr) {
94                 obj->callbackNapi_ = std::make_shared<AudioHapticPlayerCallbackNapi>(env);
95                 CHECK_AND_RETURN_RET_LOG(obj->callbackNapi_ != nullptr, result, "No memory");
96                 int32_t ret = obj->audioHapticPlayer_->SetAudioHapticPlayerCallback(obj->callbackNapi_);
97                 MEDIA_LOGI("Constructor: SetAudioHapticPlayerCallback %{public}s",
98                     ret == 0 ? "succeess" : "failed");
99             }
100 
101             status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
102                 AudioHapticPlayerNapi::Destructor, nullptr, nullptr);
103             if (status == napi_ok) {
104                 obj.release();
105                 return thisVar;
106             } else {
107                 MEDIA_LOGE("Failed to wrap the native audioHapticPlayer object with JS.");
108             }
109         }
110     }
111 
112     return result;
113 }
114 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)115 void AudioHapticPlayerNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
116 {
117     AudioHapticPlayerNapi *audioHapticPlayerHelper = reinterpret_cast<AudioHapticPlayerNapi*>(nativeObject);
118     if (audioHapticPlayerHelper != nullptr) {
119         audioHapticPlayerHelper->~AudioHapticPlayerNapi();
120     }
121 }
122 
CreatePlayerInstance(napi_env env,std::shared_ptr<AudioHapticPlayer> & audioHapticPlayer)123 napi_value AudioHapticPlayerNapi::CreatePlayerInstance(napi_env env,
124     std::shared_ptr<AudioHapticPlayer> &audioHapticPlayer)
125 {
126     napi_status status;
127     napi_value result = nullptr;
128     napi_value ctor;
129 
130     status = napi_get_reference_value(env, sConstructor_, &ctor);
131     if (status == napi_ok) {
132         sAudioHapticPlayer_ = audioHapticPlayer;
133         status = napi_new_instance(env, ctor, 0, nullptr, &result);
134         if (status == napi_ok) {
135             return result;
136         } else {
137             MEDIA_LOGE("CreatePlayerInstance: New instance could not be obtained.");
138         }
139     }
140 
141     napi_get_undefined(env, &result);
142     return result;
143 }
144 
IsHapticsRampSupported(napi_env env,napi_callback_info info)145 napi_value AudioHapticPlayerNapi::IsHapticsRampSupported(napi_env env, napi_callback_info info)
146 {
147     napi_value result = nullptr;
148     napi_get_undefined(env, &result);
149 
150     if (!AudioHapticCommonNapi::VerifySelfSystemPermission()) {
151         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_PERMISSION_DENIED);
152         return result;
153     }
154 
155     void *native = nullptr;
156     napi_value argv[ARGS_ONE] = {0};
157     if (!AudioHapticCommonNapi::InitNormalFunc(env, info, &native, argv, ARGS_ZERO)) {
158         return result;
159     }
160 
161     auto *audioHapticPlayerNapi = reinterpret_cast<AudioHapticPlayerNapi *>(native);
162     if (audioHapticPlayerNapi == nullptr || audioHapticPlayerNapi->audioHapticPlayer_ == nullptr) {
163         MEDIA_LOGE("IsHapticsIntensityAdjustmentSupported: unwrap failure!");
164         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_SERVICE_DIED);
165         return result;
166     }
167     bool isSupported = audioHapticPlayerNapi->audioHapticPlayer_->IsHapticsRampSupported();
168 
169     napi_get_boolean(env, isSupported, &result);
170     return result;
171 }
172 
IsHapticsIntensityAdjustmentSupported(napi_env env,napi_callback_info info)173 napi_value AudioHapticPlayerNapi::IsHapticsIntensityAdjustmentSupported(napi_env env,
174                                                                         napi_callback_info info)
175 {
176     napi_value result = nullptr;
177     napi_get_undefined(env, &result);
178 
179     if (!AudioHapticCommonNapi::VerifySelfSystemPermission()) {
180         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_PERMISSION_DENIED);
181         return result;
182     }
183 
184     void *native = nullptr;
185     napi_value argv[ARGS_ONE] = {0};
186     if (!AudioHapticCommonNapi::InitNormalFunc(env, info, &native, argv, ARGS_ZERO)) {
187         return result;
188     }
189 
190     auto *audioHapticPlayerNapi = reinterpret_cast<AudioHapticPlayerNapi *>(native);
191     if (audioHapticPlayerNapi == nullptr || audioHapticPlayerNapi->audioHapticPlayer_ == nullptr) {
192         MEDIA_LOGE("IsHapticsIntensityAdjustmentSupported: unwrap failure!");
193         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_SERVICE_DIED);
194         return result;
195     }
196     bool isSupported = audioHapticPlayerNapi->audioHapticPlayer_->IsHapticsIntensityAdjustmentSupported();
197 
198     napi_get_boolean(env, isSupported, &result);
199     return result;
200 }
201 
EnableHapticsInSilentMode(napi_env env,napi_callback_info info)202 napi_value AudioHapticPlayerNapi::EnableHapticsInSilentMode(napi_env env, napi_callback_info info)
203 {
204     napi_value result = nullptr;
205     napi_get_undefined(env, &result);
206 
207     if (!AudioHapticCommonNapi::VerifySelfSystemPermission()) {
208         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_PERMISSION_DENIED);
209         return result;
210     }
211 
212     void *native = nullptr;
213     napi_value argv[ARGS_ONE] = {0};
214     if (!AudioHapticCommonNapi::InitNormalFunc(env, info, &native, argv, ARGS_ONE)) {
215         return result;
216     }
217 
218     auto *audioHapticPlayerNapi = reinterpret_cast<AudioHapticPlayerNapi *>(native);
219     if (audioHapticPlayerNapi == nullptr || audioHapticPlayerNapi->audioHapticPlayer_ == nullptr) {
220         MEDIA_LOGE("EnableHapticsInSilentMode: unwrap failure!");
221         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_SERVICE_DIED);
222         return result;
223     }
224 
225     bool enable = false;
226     if (napi_get_value_bool(env, argv[PARAM0], &enable) != napi_ok) {
227         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "input param is invalid");
228         return result;
229     }
230 
231     int32_t ret = audioHapticPlayerNapi->audioHapticPlayer_->EnableHapticsInSilentMode(enable);
232     if (ret == NAPI_ERR_OPERATE_NOT_ALLOWED) {
233         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_OPERATE_NOT_ALLOWED);
234         return result;
235     }
236     return result;
237 }
238 
IsMuted(napi_env env,napi_callback_info info)239 napi_value AudioHapticPlayerNapi::IsMuted(napi_env env, napi_callback_info info)
240 {
241     napi_value result = nullptr;
242     napi_get_boolean(env, false, &result);
243 
244     size_t argc = ARGS_ONE;
245     napi_value argv[ARGS_ONE] = {0};
246     napi_value thisVar = nullptr;
247 
248     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
249     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "IsMuted: napi_get_cb_info fail");
250     if (argc != ARGS_ONE) {
251         MEDIA_LOGE("IsMuted: requires 1 parameters");
252         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified");
253         return result;
254     }
255 
256     void *native = nullptr;
257     status = napi_unwrap(env, thisVar, &native);
258     auto *audioHapticPlayerNapi = reinterpret_cast<AudioHapticPlayerNapi *>(native);
259     if (status != napi_ok || audioHapticPlayerNapi == nullptr) {
260         MEDIA_LOGE("IsMuted: unwrap failure!");
261         return result;
262     }
263 
264     napi_valuetype valueType = napi_undefined;
265     napi_typeof(env, argv[PARAM0], &valueType);
266     int32_t jsAudioHapticType = -1;
267     if (valueType == napi_number) {
268         napi_get_value_int32(env, argv[PARAM0], &jsAudioHapticType);
269     }
270     if (!IsLegalAudioHapticType(jsAudioHapticType)) {
271         MEDIA_LOGE("IsMuted: the param type mismatch");
272         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID,
273             "parameter verification failed: The param of type must be enum AudioHapticType");
274         return result;
275     }
276 
277     AudioHapticType audioHapticType = static_cast<AudioHapticType>(jsAudioHapticType);
278     bool isMuted = audioHapticPlayerNapi->audioHapticPlayer_->IsMuted(audioHapticType);
279     napi_get_boolean(env, isMuted, &result);
280 
281     return result;
282 }
283 
IsLegalAudioHapticType(int32_t audioHapticType)284 bool AudioHapticPlayerNapi::IsLegalAudioHapticType(int32_t audioHapticType)
285 {
286     switch (audioHapticType) {
287         case AUDIO_HAPTIC_TYPE_AUDIO:
288         case AUDIO_HAPTIC_TYPE_HAPTIC:
289             return true;
290         default:
291             break;
292     }
293     MEDIA_LOGE("IsLegalAudioHapticType: audioHapticType %{public}d is invalid", audioHapticType);
294     return false;
295 }
296 
IsLegalVolumeOrIntensity(double number)297 bool AudioHapticPlayerNapi::IsLegalVolumeOrIntensity(double number)
298 {
299     return number >= 0.0 && number <= 1.0;
300 }
301 
JudgeVolume(napi_env env,std::unique_ptr<VolumeContext> & asyncContext)302 bool AudioHapticPlayerNapi::JudgeVolume(napi_env env, std::unique_ptr<VolumeContext>& asyncContext)
303 {
304     napi_valuetype valueType = napi_undefined;
305     napi_typeof(env, asyncContext->argv[PARAM0], &valueType);
306     double volume = -1.00;
307     if (valueType == napi_number) {
308         napi_get_value_double(env, asyncContext->argv[PARAM0], &volume);
309     }
310     if (!IsLegalVolumeOrIntensity(volume)) {
311         MEDIA_LOGE("SetVolume: the param is invalid");
312         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred, NAPI_ERR_PARAM_OUT_OF_RANGE);
313         return false;
314     }
315 
316     asyncContext->volume = static_cast<float>(std::round(volume * PRECISION) / PRECISION);
317     return true;
318 }
319 
JudgeIntensity(napi_env env,std::unique_ptr<VibrationContext> & asyncContext)320 bool AudioHapticPlayerNapi::JudgeIntensity(napi_env env, std::unique_ptr<VibrationContext>& asyncContext)
321 {
322     napi_valuetype valueType = napi_undefined;
323     napi_typeof(env, asyncContext->argv[PARAM0], &valueType);
324     double intensity = -1.00;
325     if (valueType == napi_number) {
326         napi_get_value_double(env, asyncContext->argv[PARAM0], &intensity);
327     }
328     if (!IsLegalVolumeOrIntensity(intensity)) {
329         MEDIA_LOGE("SetIntensity: the param is invalid");
330         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred, NAPI_ERR_PARAM_OUT_OF_RANGE);
331         return false;
332     }
333 
334     asyncContext->intensity = static_cast<float>(std::round(intensity * PRECISION) / PRECISION);
335     return true;
336 }
337 
JudgeRamp(napi_env env,std::unique_ptr<RampContext> & asyncContext)338 bool AudioHapticPlayerNapi::JudgeRamp(napi_env env, std::unique_ptr<RampContext> &asyncContext)
339 {
340     if (napi_get_value_int32(env, asyncContext->argv[PARAM0], &asyncContext->duration) != napi_ok) {
341         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "invalid duration");
342         return false;
343     }
344     int32_t notLessThanDurationMs = 100;
345     if (asyncContext->duration < notLessThanDurationMs) {
346         MEDIA_LOGE("SetHapticsRamp: the duration is invalid");
347         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred,
348             NAPI_ERR_PARAM_OUT_OF_RANGE, "duration not less than 100 ms");
349         return false;
350     }
351 
352     double startIntensity = 0.00;
353     if (napi_get_value_double(env, asyncContext->argv[PARAM1], &startIntensity) != napi_ok) {
354         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "invalid startIntensity");
355         return false;
356     }
357     if (!IsLegalVolumeOrIntensity(startIntensity)) {
358         MEDIA_LOGE("SetHapticsRamp: startIntensity is invalid");
359         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred,
360             NAPI_ERR_PARAM_OUT_OF_RANGE, "startIntensity's value ranges from 0.00 to 1.00");
361         return false;
362     }
363     asyncContext->startIntensity = static_cast<float>(std::round(startIntensity * PRECISION) / PRECISION);
364 
365     double endIntensity = 0.00;
366     if (napi_get_value_double(env, asyncContext->argv[PARAM2], &endIntensity) != napi_ok) {
367         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "invalid endIntensity");
368         return false;
369     }
370     if (!IsLegalVolumeOrIntensity(endIntensity)) {
371         MEDIA_LOGE("SetHapticsRamp: endIntensity is invalid");
372         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred,
373             NAPI_ERR_PARAM_OUT_OF_RANGE, "endIntensity's value ranges from 0.00 to 1.00");
374         return false;
375     }
376     asyncContext->endIntensity = static_cast<float>(std::round(endIntensity * PRECISION) / PRECISION);
377 
378     return true;
379 }
380 
CommonAsyncCallbackComp(napi_env env,napi_status status,void * data)381 void AudioHapticPlayerNapi::CommonAsyncCallbackComp(napi_env env, napi_status status, void *data)
382 {
383     auto context = static_cast<AudioHapticPlayerAsyncContext *>(data);
384     napi_value result[2] = {};
385 
386     napi_get_undefined(env, &result[PARAM1]);
387     if (!context->status) {
388         napi_get_undefined(env, &result[PARAM0]);
389     } else {
390         napi_value message = nullptr;
391         napi_create_string_utf8(env, "Error: Operation is not supported or failed", NAPI_AUTO_LENGTH, &message);
392         napi_create_error(env, nullptr, message, &result[PARAM0]);
393     }
394 
395     if (context->deferred) {
396         if (!context->status) {
397             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
398         } else {
399             napi_reject_deferred(env, context->deferred, result[PARAM0]);
400         }
401     }
402     napi_delete_async_work(env, context->work);
403 
404     delete context;
405     context = nullptr;
406 }
407 
SetHapticsIntensity(napi_env env,napi_callback_info info)408 napi_value AudioHapticPlayerNapi::SetHapticsIntensity(napi_env env, napi_callback_info info)
409 {
410     std::unique_ptr<VibrationContext> asyncContext = std::make_unique<VibrationContext>();
411     napi_value promise = nullptr;
412     if (!AudioHapticCommonNapi::InitPromiseFunc(env, info, asyncContext.get(), &promise, ARGS_ONE)) {
413         return promise;
414     }
415     if (!AudioHapticCommonNapi::VerifySelfSystemPermission()) {
416         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred, NAPI_ERR_PERMISSION_DENIED);
417         return promise;
418     }
419     if (!JudgeIntensity(env, asyncContext)) {
420         return promise;
421     }
422 
423     napi_value funcName = nullptr;
424     napi_create_string_utf8(env, "SetVibrationIntensity", NAPI_AUTO_LENGTH, &funcName);
425     napi_status status = napi_create_async_work(env, nullptr, funcName,
426         [](napi_env env, void *data) {
427             auto context = static_cast<VibrationContext*>(data);
428             AudioHapticPlayerNapi* object = reinterpret_cast<AudioHapticPlayerNapi*>(context->objectInfo);
429             if (object == nullptr || object->audioHapticPlayer_ == nullptr) {
430                 context->result = NAPI_ERR_SERVICE_DIED;
431             } else {
432                 context->result = object->audioHapticPlayer_->SetHapticIntensity(context->intensity * PRECISION);
433             }
434         },
435         [](napi_env env, napi_status status, void *data) {
436             auto context = static_cast<VibrationContext*>(data);
437             if (context->deferred) {
438                 if (context->result == 0) {
439                     napi_value result;
440                     napi_get_undefined(env, &result);
441                     napi_resolve_deferred(env, context->deferred, result);
442                 } else {
443                     AudioHapticCommonNapi::PromiseReject(env, context->deferred, context->result);
444                 }
445             }
446             napi_delete_async_work(env, context->work);
447             delete context;
448             context = nullptr;
449         }, static_cast<void*>(asyncContext.get()), &asyncContext->work);
450     if (status != napi_ok) {
451         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred, status, "Failed to get create async work");
452     } else {
453         napi_queue_async_work(env, asyncContext->work);
454         asyncContext.release();
455     }
456 
457     return promise;
458 }
459 
SetVolume(napi_env env,napi_callback_info info)460 napi_value AudioHapticPlayerNapi::SetVolume(napi_env env, napi_callback_info info)
461 {
462     std::unique_ptr<VolumeContext> asyncContext = std::make_unique<VolumeContext>();
463     napi_value promise = nullptr;
464     if (!AudioHapticCommonNapi::InitPromiseFunc(env, info, asyncContext.get(), &promise, ARGS_ONE)) {
465         return promise;
466     }
467 
468     if (!JudgeVolume(env, asyncContext)) {
469         return promise;
470     }
471 
472     napi_value funcName = nullptr;
473     napi_create_string_utf8(env, "SetVolume", NAPI_AUTO_LENGTH, &funcName);
474     napi_status status = napi_create_async_work(
475         env,
476         nullptr,
477         funcName,
478         [](napi_env env, void *data) {
479             auto context = static_cast<VolumeContext*>(data);
480             AudioHapticPlayerNapi* object = reinterpret_cast<AudioHapticPlayerNapi*>(context->objectInfo);
481 
482             context->result = object->audioHapticPlayer_->SetVolume(context->volume);
483         },
484         [](napi_env env, napi_status status, void *data) {
485             auto context = static_cast<VolumeContext*>(data);
486             if (context->deferred) {
487                 if (context->result == 0) {
488                     napi_value result;
489                     napi_get_undefined(env, &result);
490                     napi_resolve_deferred(env, context->deferred, result);
491                 } else {
492                     AudioHapticCommonNapi::PromiseReject(env, context->deferred,
493                         context->result, "Failed to set volume");
494                 }
495             }
496             napi_delete_async_work(env, context->work);
497             delete context;
498             context = nullptr;
499         },
500         static_cast<void*>(asyncContext.get()),
501         &asyncContext->work);
502     if (status != napi_ok) {
503         MEDIA_LOGE("Start: Failed to get create async work");
504         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred,
505             status, "Failed to get create async work");
506     } else {
507         napi_queue_async_work(env, asyncContext->work);
508         asyncContext.release();
509     }
510 
511     return promise;
512 }
513 
SetHapticsRamp(napi_env env,napi_callback_info info)514 napi_value AudioHapticPlayerNapi::SetHapticsRamp(napi_env env, napi_callback_info info)
515 {
516     std::unique_ptr<RampContext> asyncContext = std::make_unique<RampContext>();
517     napi_value promise = nullptr;
518     if (!AudioHapticCommonNapi::InitPromiseFunc(env, info, asyncContext.get(), &promise, ARGS_THREE)) {
519         return promise;
520     }
521     if (!AudioHapticCommonNapi::VerifySelfSystemPermission()) {
522         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred, NAPI_ERR_PERMISSION_DENIED);
523         return promise;
524     }
525     if (!JudgeRamp(env, asyncContext)) {
526         return promise;
527     }
528     napi_value funcName = nullptr;
529     napi_create_string_utf8(env, "SetHapticsRamp", NAPI_AUTO_LENGTH, &funcName);
530     napi_status status = napi_create_async_work(env, nullptr, funcName,
531         [](napi_env env, void *data) {
532             auto context = static_cast<RampContext*>(data);
533             AudioHapticPlayerNapi* object = reinterpret_cast<AudioHapticPlayerNapi*>(context->objectInfo);
534             if (object != nullptr && object->audioHapticPlayer_ != nullptr) {
535                 context->result = object->audioHapticPlayer_->SetHapticsRamp(context->duration,
536                     context->startIntensity * PRECISION, context->endIntensity * PRECISION);
537             }
538         },
539         [](napi_env env, napi_status status, void *data) {
540             auto context = static_cast<RampContext*>(data);
541             if (context->deferred) {
542                 if (context->result == 0) {
543                     napi_value result;
544                     napi_get_undefined(env, &result);
545                     napi_resolve_deferred(env, context->deferred, result);
546                 } else {
547                     AudioHapticCommonNapi::PromiseReject(env, context->deferred, context->result);
548                 }
549             }
550             napi_delete_async_work(env, context->work);
551             delete context;
552             context = nullptr;
553         }, static_cast<void*>(asyncContext.get()), &asyncContext->work);
554     if (status != napi_ok) {
555         MEDIA_LOGE("Start: Failed to get create async work");
556         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred, status, "Failed to get create async work");
557     } else {
558         napi_queue_async_work(env, asyncContext->work);
559         asyncContext.release();
560     }
561     return promise;
562 }
563 
SetLoop(napi_env env,napi_callback_info info)564 napi_value AudioHapticPlayerNapi::SetLoop(napi_env env, napi_callback_info info)
565 {
566     std::unique_ptr<LoopContext> asyncContext = std::make_unique<LoopContext>();
567     napi_value promise = nullptr;
568     if (!AudioHapticCommonNapi::InitPromiseFunc(env, info, asyncContext.get(), &promise, ARGS_ONE)) {
569         return promise;
570     }
571 
572     if (napi_get_value_bool(env, asyncContext->argv[PARAM0], &asyncContext->loop) != napi_ok) {
573         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "input param is invalid");
574         return promise;
575     }
576 
577     napi_value funcName = nullptr;
578     napi_create_string_utf8(env, "SetLoop", NAPI_AUTO_LENGTH, &funcName);
579     napi_status status = napi_create_async_work(env, nullptr, funcName,
580         [](napi_env env, void *data) {
581             auto context = static_cast<LoopContext*>(data);
582             AudioHapticPlayerNapi* object = reinterpret_cast<AudioHapticPlayerNapi*>(context->objectInfo);
583             if (object != nullptr && object->audioHapticPlayer_ != nullptr) {
584                 context->result = object->audioHapticPlayer_->SetLoop(context->loop);
585             }
586         },
587         [](napi_env env, napi_status status, void *data) {
588             auto context = static_cast<LoopContext*>(data);
589             if (context->deferred) {
590                 if (context->result == 0) {
591                     napi_value result;
592                     napi_get_undefined(env, &result);
593                     napi_resolve_deferred(env, context->deferred, result);
594                 } else {
595                     AudioHapticCommonNapi::PromiseReject(env, context->deferred, context->result);
596                 }
597             }
598             napi_delete_async_work(env, context->work);
599             delete context;
600             context = nullptr;
601         }, static_cast<void*>(asyncContext.get()), &asyncContext->work);
602     if (status != napi_ok) {
603         MEDIA_LOGE("Start: Failed to get create async work");
604         AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred,
605             status, "Failed to get create async work");
606     } else {
607         napi_queue_async_work(env, asyncContext->work);
608         asyncContext.release();
609     }
610 
611     return promise;
612 }
613 
Start(napi_env env,napi_callback_info info)614 napi_value AudioHapticPlayerNapi::Start(napi_env env, napi_callback_info info)
615 {
616     napi_value result = nullptr;
617     napi_value resource = nullptr;
618     size_t argc = ARGS_ONE;
619     napi_value argv[ARGS_ONE] = {0};
620     napi_value thisVar = nullptr;
621 
622     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
623     napi_get_undefined(env, &result);
624     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "Start: napi_get_cb_info fail");
625     if (argc != 0) {
626         MEDIA_LOGE("Start: requires 0 parameters");
627         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
628         return result;
629     }
630 
631     std::unique_ptr<AudioHapticPlayerAsyncContext> asyncContext = std::make_unique<AudioHapticPlayerAsyncContext>();
632     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
633     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
634         napi_create_promise(env, &asyncContext->deferred, &result);
635         napi_create_string_utf8(env, "Start", NAPI_AUTO_LENGTH, &resource);
636         status = napi_create_async_work(env, nullptr, resource,
637             [](napi_env env, void *data) {
638                 AudioHapticPlayerAsyncContext *context = static_cast<AudioHapticPlayerAsyncContext*>(data);
639                 context->status = context->objectInfo->audioHapticPlayer_->Start();
640             },
641             CommonAsyncCallbackComp, static_cast<void*>(asyncContext.get()), &asyncContext->work);
642         if (status != napi_ok) {
643             MEDIA_LOGE("Start: Failed to get create async work");
644             napi_get_undefined(env, &result);
645         } else {
646             napi_queue_async_work(env, asyncContext->work);
647             asyncContext.release();
648         }
649     }
650 
651     return result;
652 }
653 
Stop(napi_env env,napi_callback_info info)654 napi_value AudioHapticPlayerNapi::Stop(napi_env env, napi_callback_info info)
655 {
656     napi_value result = nullptr;
657     napi_value resource = nullptr;
658     size_t argc = ARGS_ONE;
659     napi_value argv[ARGS_ONE] = {0};
660     napi_value thisVar = nullptr;
661 
662     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
663     napi_get_undefined(env, &result);
664     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "Stop: napi_get_cb_info fail");
665     if (argc != 0) {
666         MEDIA_LOGE("Stop: requires 0 parameters");
667         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
668         return result;
669     }
670 
671     std::unique_ptr<AudioHapticPlayerAsyncContext> asyncContext = std::make_unique<AudioHapticPlayerAsyncContext>();
672     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
673     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
674         napi_create_promise(env, &asyncContext->deferred, &result);
675         napi_create_string_utf8(env, "Stop", NAPI_AUTO_LENGTH, &resource);
676         status = napi_create_async_work(env, nullptr, resource,
677             [](napi_env env, void *data) {
678                 AudioHapticPlayerAsyncContext *context = static_cast<AudioHapticPlayerAsyncContext*>(data);
679                 context->status = context->objectInfo->audioHapticPlayer_->Stop();
680             },
681             CommonAsyncCallbackComp, static_cast<void*>(asyncContext.get()), &asyncContext->work);
682         if (status != napi_ok) {
683             MEDIA_LOGE("Stop: Failed to get create async work");
684             napi_get_undefined(env, &result);
685         } else {
686             napi_queue_async_work(env, asyncContext->work);
687             asyncContext.release();
688         }
689     }
690 
691     return result;
692 }
693 
Release(napi_env env,napi_callback_info info)694 napi_value AudioHapticPlayerNapi::Release(napi_env env, napi_callback_info info)
695 {
696     napi_value result = nullptr;
697     napi_value resource = nullptr;
698     size_t argc = ARGS_ONE;
699     napi_value argv[ARGS_ONE] = {0};
700     napi_value thisVar = nullptr;
701 
702     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
703     napi_get_undefined(env, &result);
704     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "Release: napi_get_cb_info fail");
705     if (argc != 0) {
706         MEDIA_LOGE("Release: requires 0 parameters");
707         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
708         return result;
709     }
710 
711     std::unique_ptr<AudioHapticPlayerAsyncContext> asyncContext = std::make_unique<AudioHapticPlayerAsyncContext>();
712     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
713     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
714         napi_create_promise(env, &asyncContext->deferred, &result);
715         napi_create_string_utf8(env, "Release", NAPI_AUTO_LENGTH, &resource);
716         status = napi_create_async_work(env, nullptr, resource,
717             [](napi_env env, void *data) {
718                 AudioHapticPlayerAsyncContext *context = static_cast<AudioHapticPlayerAsyncContext*>(data);
719                 context->status = context->objectInfo->audioHapticPlayer_->Release();
720             },
721             CommonAsyncCallbackComp, static_cast<void*>(asyncContext.get()), &asyncContext->work);
722         if (status != napi_ok) {
723             MEDIA_LOGE("Release: Failed to get create async work");
724             napi_get_undefined(env, &result);
725         } else {
726             napi_queue_async_work(env, asyncContext->work);
727             asyncContext.release();
728         }
729     }
730 
731     return result;
732 }
733 
On(napi_env env,napi_callback_info info)734 napi_value AudioHapticPlayerNapi::On(napi_env env, napi_callback_info info)
735 {
736     napi_value result = nullptr;
737     size_t argc = ARGS_TWO;
738     napi_value argv[ARGS_TWO] = {nullptr};
739     napi_value jsThis = nullptr;
740     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
741     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, result, "On: napi_get_cb_info fail");
742     if (argc != ARGS_TWO) {
743         MEDIA_LOGE("On: requires 2 parameters");
744         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
745         return result;
746     }
747 
748     napi_valuetype argvType = napi_undefined;
749     napi_typeof(env, argv[PARAM0], &argvType);
750     if (argvType != napi_string) {
751         MEDIA_LOGE("On: the first parameter must be napi_string");
752         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
753         return result;
754     }
755     std::string callbackName = AudioHapticCommonNapi::GetStringArgument(env, argv[0]);
756     MEDIA_LOGI("On: callbackName: %{public}s", callbackName.c_str());
757 
758     napi_typeof(env, argv[PARAM1], &argvType);
759     if (argvType != napi_function) {
760         MEDIA_LOGE("On: the second parameter must be napi_function");
761         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
762         return result;
763     }
764 
765     return RegisterCallback(env, jsThis, argv, callbackName);
766 }
767 
RegisterCallback(napi_env env,napi_value jsThis,napi_value * argv,const std::string & cbName)768 napi_value AudioHapticPlayerNapi::RegisterCallback(napi_env env, napi_value jsThis, napi_value* argv,
769     const std::string& cbName)
770 {
771     napi_value result = nullptr;
772     napi_get_undefined(env, &result);
773 
774     AudioHapticPlayerNapi *audioHapticPlayerNapi = nullptr;
775     napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&audioHapticPlayerNapi));
776     if (status != napi_ok || audioHapticPlayerNapi == nullptr || audioHapticPlayerNapi->audioHapticPlayer_ == nullptr) {
777         MEDIA_LOGE("RegisterCallback: Failed to get audioHapticPlayer_");
778         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_OPERATE_NOT_ALLOWED);
779         return result;
780     }
781 
782     if (!cbName.compare(AUDIO_INTERRUPT_CALLBACK_NAME) ||
783         !cbName.compare(END_OF_STREAM_CALLBACK_NAME)) {
784         result = RegisterAudioHapticPlayerCallback(env, argv, cbName, audioHapticPlayerNapi);
785     } else {
786         MEDIA_LOGE("RegisterCallback: the callback name: %{public}s is not supported", cbName.c_str());
787         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
788         return result;
789     }
790 
791     return result;
792 }
793 
RegisterAudioHapticPlayerCallback(napi_env env,napi_value * argv,const std::string & cbName,AudioHapticPlayerNapi * audioHapticPlayerNapi)794 napi_value AudioHapticPlayerNapi::RegisterAudioHapticPlayerCallback(napi_env env, napi_value* argv,
795     const std::string& cbName, AudioHapticPlayerNapi *audioHapticPlayerNapi)
796 {
797     napi_value result = nullptr;
798     napi_get_undefined(env, &result);
799 
800     if (audioHapticPlayerNapi->callbackNapi_ == nullptr) {
801         MEDIA_LOGE("RegisterAudioHapticPlayerCallback: callbackNapi_ is null");
802         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_OPERATE_NOT_ALLOWED);
803         return result;
804     }
805     audioHapticPlayerNapi->callbackNapi_->SaveCallbackReference(cbName, argv[PARAM1]);
806 
807     return result;
808 }
809 
Off(napi_env env,napi_callback_info info)810 napi_value AudioHapticPlayerNapi::Off(napi_env env, napi_callback_info info)
811 {
812     napi_value result = nullptr;
813     size_t argc = ARGS_TWO;
814     napi_value argv[ARGS_TWO] = {nullptr};
815     napi_value jsThis = nullptr;
816     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
817     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, result, "Off: napi_get_cb_info fail");
818     if (argc != ARGS_ONE && argc != ARGS_TWO) {
819         MEDIA_LOGE("Off: requires 1 or 2 parameters");
820         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
821         return result;
822     }
823 
824     napi_valuetype argvType = napi_undefined;
825     napi_typeof(env, argv[PARAM0], &argvType);
826     if (argvType != napi_string) {
827         MEDIA_LOGE("Off: the parameter must be napi_string");
828         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
829         return result;
830     }
831     std::string callbackName = AudioHapticCommonNapi::GetStringArgument(env, argv[0]);
832     MEDIA_LOGI("Off: callbackName: %{public}s", callbackName.c_str());
833 
834     return UnregisterCallback(env, jsThis, callbackName);
835 }
836 
UnregisterCallback(napi_env env,napi_value jsThis,const std::string & cbName)837 napi_value AudioHapticPlayerNapi::UnregisterCallback(napi_env env, napi_value jsThis, const std::string &cbName)
838 {
839     napi_value result = nullptr;
840     napi_get_undefined(env, &result);
841 
842     AudioHapticPlayerNapi *audioHapticPlayerNapi = nullptr;
843     napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&audioHapticPlayerNapi));
844     if (status != napi_ok || audioHapticPlayerNapi == nullptr || audioHapticPlayerNapi->audioHapticPlayer_ == nullptr) {
845         MEDIA_LOGE("UnregisterCallback: Failed to get audioHapticPlayer_");
846         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_OPERATE_NOT_ALLOWED);
847         return result;
848     }
849 
850     if (!cbName.compare(AUDIO_INTERRUPT_CALLBACK_NAME) ||
851         !cbName.compare(END_OF_STREAM_CALLBACK_NAME)) {
852         result = UnregisterAudioHapticPlayerCallback(env, cbName, audioHapticPlayerNapi);
853     } else {
854         MEDIA_LOGE("UnregisterCallback: the callback name: %{public}s is not supported", cbName.c_str());
855         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
856         return result;
857     }
858 
859     return result;
860 }
861 
UnregisterAudioHapticPlayerCallback(napi_env env,const std::string & cbName,AudioHapticPlayerNapi * audioHapticPlayerNapi)862 napi_value AudioHapticPlayerNapi::UnregisterAudioHapticPlayerCallback(napi_env env, const std::string& cbName,
863     AudioHapticPlayerNapi *audioHapticPlayerNapi)
864 {
865     napi_value result = nullptr;
866     napi_get_undefined(env, &result);
867 
868     if (audioHapticPlayerNapi->callbackNapi_ == nullptr) {
869         MEDIA_LOGE("RegisterAudioHapticPlayerCallback: callbackNapi_ is null");
870         AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_OPERATE_NOT_ALLOWED);
871         return result;
872     }
873     audioHapticPlayerNapi->callbackNapi_->RemoveCallbackReference(cbName);
874 
875     return result;
876 }
877 } // namespace Media
878 } // namespace OHOS