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