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_manager_napi.h"
17
18 #include "audio_haptic_file_descriptor_napi.h"
19 #include "audio_haptic_player_napi.h"
20
21 #include "audio_haptic_log.h"
22
23 namespace {
24 const int32_t SIZE = 1024;
25
26 const int ERROR = -1;
27 const int SUCCESS = 0;
28
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticManagerNapi"};
30 }
31
32 namespace OHOS {
33 namespace Media {
34 thread_local napi_ref AudioHapticManagerNapi::sConstructor_ = nullptr;
35 thread_local napi_ref AudioHapticManagerNapi::sAudioLatencyMode_ = nullptr;
36 thread_local napi_ref AudioHapticManagerNapi::sAudioHapticType_ = nullptr;
37
AudioHapticManagerNapi()38 AudioHapticManagerNapi::AudioHapticManagerNapi()
39 : env_(nullptr), audioHapticMgrClient_(nullptr) {}
40
41 AudioHapticManagerNapi::~AudioHapticManagerNapi() = default;
42
AddNamedProperty(napi_env env,napi_value object,const std::string name,int32_t enumValue)43 napi_status AudioHapticManagerNapi::AddNamedProperty(napi_env env, napi_value object, const std::string name,
44 int32_t enumValue)
45 {
46 napi_status status;
47 napi_value napiValue;
48
49 status = napi_create_int32(env, enumValue, &napiValue);
50 if (status == napi_ok) {
51 status = napi_set_named_property(env, object, name.c_str(), napiValue);
52 }
53
54 return status;
55 }
56
CreateAudioLatencyModeObject(napi_env env)57 napi_value AudioHapticManagerNapi::CreateAudioLatencyModeObject(napi_env env)
58 {
59 napi_value result = nullptr;
60 napi_status status;
61 std::string propName;
62 int32_t refCount = 1;
63
64 status = napi_create_object(env, &result);
65 if (status == napi_ok) {
66 for (auto &iter: audioLatencyModeMap) {
67 propName = iter.first;
68 status = AddNamedProperty(env, result, propName, iter.second);
69 if (status != napi_ok) {
70 MEDIA_LOGE("CreateAudioLatencyModeObject: Failed to add named prop!");
71 break;
72 }
73 propName.clear();
74 }
75 if (status == napi_ok) {
76 status = napi_create_reference(env, result, refCount, &sAudioLatencyMode_);
77 if (status == napi_ok) {
78 return result;
79 }
80 }
81 }
82 napi_get_undefined(env, &result);
83
84 return result;
85 }
86
CreateAudioHapticTypeObject(napi_env env)87 napi_value AudioHapticManagerNapi::CreateAudioHapticTypeObject(napi_env env)
88 {
89 napi_value result = nullptr;
90 napi_status status = napi_create_object(env, &result);
91 if (status == napi_ok) {
92 std::string propName;
93 for (auto &iter: audioHapticTypeMap) {
94 propName = iter.first;
95 status = AddNamedProperty(env, result, propName, iter.second);
96 if (status != napi_ok) {
97 MEDIA_LOGE("CreateAudioHapticTypeObject: Failed to add named prop!");
98 break;
99 }
100 propName.clear();
101 }
102 if (status == napi_ok) {
103 int32_t refCount = 1;
104 status = napi_create_reference(env, result, refCount, &sAudioHapticType_);
105 if (status == napi_ok) {
106 return result;
107 }
108 }
109 }
110 napi_get_undefined(env, &result);
111
112 return result;
113 }
114
Init(napi_env env,napi_value exports)115 napi_value AudioHapticManagerNapi::Init(napi_env env, napi_value exports)
116 {
117 napi_status status;
118 napi_value ctorObj;
119 int32_t refCount = 1;
120
121 napi_property_descriptor audioHapticMgrProp[] = {
122 DECLARE_NAPI_FUNCTION("registerSource", RegisterSource),
123 DECLARE_NAPI_FUNCTION("registerSourceFromFd", RegisterSourceFromFd),
124 DECLARE_NAPI_FUNCTION("unregisterSource", UnregisterSource),
125 DECLARE_NAPI_FUNCTION("setAudioLatencyMode", SetAudioLatencyMode),
126 DECLARE_NAPI_FUNCTION("setStreamUsage", SetStreamUsage),
127 DECLARE_NAPI_FUNCTION("createPlayer", CreatePlayer),
128 };
129
130 napi_property_descriptor staticProp[] = {
131 DECLARE_NAPI_STATIC_FUNCTION("getAudioHapticManager", GetAudioHapticManager),
132 DECLARE_NAPI_PROPERTY("AudioLatencyMode", CreateAudioLatencyModeObject(env)),
133 DECLARE_NAPI_PROPERTY("AudioHapticType", CreateAudioHapticTypeObject(env)),
134 };
135
136 status = napi_define_class(env, AUDIO_HAPTIC_MANAGER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct,
137 nullptr, sizeof(audioHapticMgrProp) / sizeof(audioHapticMgrProp[0]), audioHapticMgrProp, &ctorObj);
138 if (status == napi_ok) {
139 if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
140 if (napi_set_named_property(env, exports,
141 AUDIO_HAPTIC_MANAGER_NAPI_CLASS_NAME.c_str(), ctorObj) == napi_ok &&
142 napi_define_properties(env, exports,
143 sizeof(staticProp) / sizeof(staticProp[0]), staticProp) == napi_ok) {
144 return exports;
145 }
146 }
147 }
148
149 return nullptr;
150 }
151
Construct(napi_env env,napi_callback_info info)152 napi_value AudioHapticManagerNapi::Construct(napi_env env, napi_callback_info info)
153 {
154 napi_status status;
155 napi_value result = nullptr;
156 napi_value thisVar = nullptr;
157
158 napi_get_undefined(env, &result);
159 status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
160 if (status == napi_ok && thisVar != nullptr) {
161 std::unique_ptr<AudioHapticManagerNapi> obj = std::make_unique<AudioHapticManagerNapi>();
162 if (obj != nullptr) {
163 obj->env_ = env;
164 obj->audioHapticMgrClient_ = AudioHapticManagerFactory::CreateAudioHapticManager();
165 if (obj->audioHapticMgrClient_ == nullptr) {
166 MEDIA_LOGE("Failed to create audioHapticMgrClient_ instance.");
167 return result;
168 }
169
170 status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
171 AudioHapticManagerNapi::Destructor, nullptr, nullptr);
172 if (status == napi_ok) {
173 obj.release();
174 return thisVar;
175 } else {
176 MEDIA_LOGE("Failed to wrap the native AudioHapticManager object with JS.");
177 }
178 }
179 }
180
181 return result;
182 }
183
Destructor(napi_env env,void * nativeObject,void * finalizeHint)184 void AudioHapticManagerNapi::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
185 {
186 AudioHapticManagerNapi *audioHapticManagerhelper = reinterpret_cast<AudioHapticManagerNapi*>(nativeObject);
187 if (audioHapticManagerhelper != nullptr) {
188 audioHapticManagerhelper->~AudioHapticManagerNapi();
189 }
190 }
191
GetAudioHapticManager(napi_env env,napi_callback_info info)192 napi_value AudioHapticManagerNapi::GetAudioHapticManager(napi_env env, napi_callback_info info)
193 {
194 napi_status status;
195 napi_value result = nullptr;
196 napi_value ctor;
197
198 status = napi_get_reference_value(env, sConstructor_, &ctor);
199 if (status == napi_ok) {
200 status = napi_new_instance(env, ctor, 0, nullptr, &result);
201 if (status == napi_ok) {
202 return result;
203 } else {
204 MEDIA_LOGE("GetAudioHapticManager: new instance can not be obtained.");
205 }
206 }
207
208 napi_get_undefined(env, &result);
209 return result;
210 }
211
RegisterSourceFromFd(napi_env env,napi_callback_info info)212 napi_value AudioHapticManagerNapi::RegisterSourceFromFd(napi_env env, napi_callback_info info)
213 {
214 std::unique_ptr<RegisterFromFdContext> asyncContext = std::make_unique<RegisterFromFdContext>();
215 napi_value promise = nullptr;
216 if (!AudioHapticCommonNapi::InitPromiseFunc(env, info, asyncContext.get(), &promise, ARGS_TWO)) {
217 return promise;
218 }
219
220 AudioHapticFileDescriptor audioFd;
221 if (GetAudioHapticFileDescriptorValue(env, asyncContext->argv[PARAM0], audioFd) != SUCCESS) {
222 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "Invalid first parameter");
223 return promise;
224 }
225 asyncContext->audioFd = audioFd;
226
227 AudioHapticFileDescriptor hapticFd;
228 if (GetAudioHapticFileDescriptorValue(env, asyncContext->argv[PARAM1], hapticFd) != SUCCESS) {
229 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "Invalid second parameter");
230 return promise;
231 }
232 asyncContext->hapticFd = hapticFd;
233
234 napi_value funcName = nullptr;
235 napi_create_string_utf8(env, "RegisterSourceFromFd", NAPI_AUTO_LENGTH, &funcName);
236 napi_status status = napi_create_async_work(
237 env,
238 nullptr,
239 funcName,
240 AsyncRegisterSourceFromFd,
241 RegisterSourceFromFdAsyncCallbackComp,
242 static_cast<void*>(asyncContext.get()),
243 &asyncContext->work);
244 if (status != napi_ok) {
245 MEDIA_LOGE("Failed to get create async work");
246 AudioHapticCommonNapi::PromiseReject(env, asyncContext->deferred,
247 status, "Failed to get create async work");
248 } else {
249 napi_queue_async_work(env, asyncContext->work);
250 asyncContext.release();
251 }
252
253 return promise;
254 }
255
AsyncRegisterSourceFromFd(napi_env env,void * data)256 void AudioHapticManagerNapi::AsyncRegisterSourceFromFd(napi_env env, void *data)
257 {
258 RegisterFromFdContext *context = static_cast<RegisterFromFdContext *>(data);
259 AudioHapticManagerNapi* object = reinterpret_cast<AudioHapticManagerNapi*>(context->objectInfo);
260 if (context->audioFd.fd == -1 || context->hapticFd.fd == -1) {
261 context->sourceID = ERROR;
262 } else {
263 context->sourceID = object->audioHapticMgrClient_->
264 RegisterSourceFromFd(context->audioFd, context->hapticFd);
265 }
266 }
267
RegisterSourceFromFdAsyncCallbackComp(napi_env env,napi_status status,void * data)268 void AudioHapticManagerNapi::RegisterSourceFromFdAsyncCallbackComp(napi_env env, napi_status status, void *data)
269 {
270 RegisterFromFdContext *context = static_cast<RegisterFromFdContext *>(data);
271 napi_value result = nullptr;
272
273 if (context->deferred) {
274 if (context->sourceID > ERROR) {
275 napi_create_int32(env, context->sourceID, &result);
276 napi_resolve_deferred(env, context->deferred, result);
277 } else {
278 AudioHapticCommonNapi::PromiseReject(env, context->deferred,
279 context->sourceID, "RegisterSourceFromFd Error: Operation is not supported or failed");
280 }
281 }
282 napi_delete_async_work(env, context->work);
283
284 delete context;
285 context = nullptr;
286 }
287
GetAudioHapticFileDescriptorValue(napi_env env,napi_value object,AudioHapticFileDescriptor & audioHapticFd)288 int32_t AudioHapticManagerNapi::GetAudioHapticFileDescriptorValue(napi_env env, napi_value object,
289 AudioHapticFileDescriptor& audioHapticFd)
290 {
291 napi_value property = nullptr;
292 bool exists = false;
293 napi_valuetype valueType = napi_undefined;
294 napi_typeof(env, object, &valueType);
295 CHECK_AND_RETURN_RET_LOG(valueType == napi_object, ERROR, "type mismatch");
296
297 auto status = napi_get_named_property(env, object, "fd", &property);
298 CHECK_AND_RETURN_RET_LOG(status == napi_ok, ERROR, "No property: fd");
299 status = napi_get_value_int32(env, property, &(audioHapticFd.fd));
300 CHECK_AND_RETURN_RET_LOG(status == napi_ok, ERROR, "Invalid value: fd");
301
302 if (napi_has_named_property(env, object, "length", &exists) == napi_ok && exists) {
303 if (napi_get_named_property(env, object, "length", &property) == napi_ok) {
304 status = napi_get_value_int64(env, property, &(audioHapticFd.length));
305 CHECK_AND_RETURN_RET_LOG(status == napi_ok, ERROR, "Invalid value: length");
306 }
307 }
308
309 if (napi_has_named_property(env, object, "offset", &exists) == napi_ok && exists) {
310 if (napi_get_named_property(env, object, "offset", &property) == napi_ok) {
311 status = napi_get_value_int64(env, property, &(audioHapticFd.offset));
312 CHECK_AND_RETURN_RET_LOG(status == napi_ok, ERROR, "Invalid value: offset");
313 }
314 }
315
316 return SUCCESS;
317 }
318
RegisterSource(napi_env env,napi_callback_info info)319 napi_value AudioHapticManagerNapi::RegisterSource(napi_env env, napi_callback_info info)
320 {
321 napi_value result = nullptr;
322 napi_value resource = nullptr;
323 size_t argc = ARGS_TWO;
324 napi_value argv[ARGS_TWO] = {0};
325 char buffer[SIZE];
326 napi_value thisVar = nullptr;
327 size_t res = 0;
328
329 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
330 napi_get_undefined(env, &result);
331 CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "RegisterSource: napi_get_cb_info fail");
332 if (argc != ARGS_TWO) {
333 MEDIA_LOGE("RegisterSource: requires 2 parameters");
334 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified");
335 return result;
336 }
337
338 std::unique_ptr<AudioHapticManagerAsyncContext> asyncContext = std::make_unique<AudioHapticManagerAsyncContext>();
339 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
340 CHECK_AND_RETURN_RET_LOG(status == napi_ok && asyncContext->objectInfo != nullptr, result,
341 "RegisterSource: Failed to unwrap object");
342
343 for (size_t i = PARAM0; i < argc; i++) {
344 napi_valuetype valueType = napi_undefined;
345 napi_typeof(env, argv[i], &valueType);
346 if (i == PARAM0 && valueType == napi_string) {
347 napi_get_value_string_utf8(env, argv[i], buffer, SIZE, &res);
348 asyncContext->audioUri = std::string(buffer);
349 } else if (i == PARAM1 && valueType == napi_string) {
350 napi_get_value_string_utf8(env, argv[i], buffer, SIZE, &res);
351 asyncContext->hapticUri = std::string(buffer);
352 } else {
353 MEDIA_LOGE("RegisterSource: the param type mismatch");
354 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID,
355 "incorrect parameter types: The type of audioUri and hapticUri must be string");
356 return result;
357 }
358 }
359 napi_create_promise(env, &asyncContext->deferred, &result);
360
361 napi_create_string_utf8(env, "RegisterSource", NAPI_AUTO_LENGTH, &resource);
362 status = napi_create_async_work(env, nullptr, resource, AsyncRegisterSource,
363 RegisterSourceAsyncCallbackComp, static_cast<void*>(asyncContext.get()), &asyncContext->work);
364 if (status != napi_ok) {
365 MEDIA_LOGE("Failed to get create async work");
366 napi_get_undefined(env, &result);
367 } else {
368 napi_queue_async_work(env, asyncContext->work);
369 asyncContext.release();
370 }
371
372 return result;
373 }
374
AsyncRegisterSource(napi_env env,void * data)375 void AudioHapticManagerNapi::AsyncRegisterSource(napi_env env, void *data)
376 {
377 AudioHapticManagerAsyncContext *context = static_cast<AudioHapticManagerAsyncContext *>(data);
378 if (context->audioUri.empty() || context->hapticUri.empty()) {
379 context->status = ERROR;
380 } else {
381 context->sourceID = context->objectInfo->audioHapticMgrClient_->
382 RegisterSource(context->audioUri, context->hapticUri);
383 context->status = SUCCESS;
384 }
385 }
386
RegisterSourceAsyncCallbackComp(napi_env env,napi_status status,void * data)387 void AudioHapticManagerNapi::RegisterSourceAsyncCallbackComp(napi_env env, napi_status status, void *data)
388 {
389 auto context = static_cast<AudioHapticManagerAsyncContext *>(data);
390 napi_value result[2] = {};
391
392 if (!context->status) {
393 napi_get_undefined(env, &result[PARAM0]);
394 napi_create_int32(env, context->sourceID, &result[PARAM1]);
395 } else {
396 napi_value message = nullptr;
397 napi_create_string_utf8(env, "RegisterSource Error: Operation is not supported or failed",
398 NAPI_AUTO_LENGTH, &message);
399 napi_create_error(env, nullptr, message, &result[PARAM0]);
400 napi_get_undefined(env, &result[PARAM1]);
401 }
402
403 if (context->deferred) {
404 if (!context->status) {
405 napi_resolve_deferred(env, context->deferred, result[PARAM1]);
406 } else {
407 napi_reject_deferred(env, context->deferred, result[PARAM0]);
408 }
409 }
410 napi_delete_async_work(env, context->work);
411
412 delete context;
413 context = nullptr;
414 }
415
UnregisterSource(napi_env env,napi_callback_info info)416 napi_value AudioHapticManagerNapi::UnregisterSource(napi_env env, napi_callback_info info)
417 {
418 napi_value result = nullptr;
419 napi_value resource = nullptr;
420 size_t argc = ARGS_ONE;
421 napi_value argv[ARGS_ONE] = {0};
422 napi_value thisVar = nullptr;
423
424 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
425 napi_get_undefined(env, &result);
426 CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result,
427 "UnregisterSource: Failed to retrieve details about the callback");
428 if (argc != ARGS_ONE) {
429 MEDIA_LOGE("UnregisterSource: requires 1 parameter");
430 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified");
431 return result;
432 }
433
434 std::unique_ptr<AudioHapticManagerAsyncContext> asyncContext = std::make_unique<AudioHapticManagerAsyncContext>();
435 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
436 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
437 napi_valuetype valueType = napi_undefined;
438 napi_typeof(env, argv[PARAM0], &valueType);
439 if (valueType == napi_number) {
440 napi_get_value_int32(env, argv[PARAM0], &asyncContext->sourceID);
441 } else {
442 MEDIA_LOGE("UnregisterSource: the param type mismatch");
443 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID,
444 "incorrect parameter types: The type of id must be number");
445 return result;
446 }
447 napi_create_promise(env, &asyncContext->deferred, &result);
448
449 napi_create_string_utf8(env, "UnregisterSource", NAPI_AUTO_LENGTH, &resource);
450 status = napi_create_async_work(env, nullptr, resource,
451 [](napi_env env, void *data) {
452 AudioHapticManagerAsyncContext *context = static_cast<AudioHapticManagerAsyncContext*>(data);
453 context->status = context->objectInfo->audioHapticMgrClient_->UnregisterSource(context->sourceID);
454 },
455 UnregisterSourceAsyncCallbackComp, static_cast<void*>(asyncContext.get()), &asyncContext->work);
456 if (status != napi_ok) {
457 MEDIA_LOGE("GetRingtoneUri: Failed to get create async work");
458 napi_get_undefined(env, &result);
459 } else {
460 napi_queue_async_work(env, asyncContext->work);
461 asyncContext.release();
462 }
463 }
464
465 return result;
466 }
467
UnregisterSourceAsyncCallbackComp(napi_env env,napi_status status,void * data)468 void AudioHapticManagerNapi::UnregisterSourceAsyncCallbackComp(napi_env env, napi_status status, void *data)
469 {
470 auto context = static_cast<AudioHapticManagerAsyncContext *>(data);
471 napi_value result[2] = {};
472
473 napi_get_undefined(env, &result[PARAM1]);
474 if (!context->status) {
475 napi_get_undefined(env, &result[PARAM0]);
476 } else {
477 napi_value message = nullptr;
478 napi_create_string_utf8(env, "UnregisterSource Error: Operation is not supported or failed",
479 NAPI_AUTO_LENGTH, &message);
480 napi_create_error(env, nullptr, message, &result[PARAM0]);
481 }
482
483 if (context->deferred) {
484 if (!context->status) {
485 napi_resolve_deferred(env, context->deferred, result[PARAM1]);
486 } else {
487 napi_reject_deferred(env, context->deferred, result[PARAM0]);
488 }
489 }
490 napi_delete_async_work(env, context->work);
491
492 delete context;
493 context = nullptr;
494 }
495
SetAudioLatencyMode(napi_env env,napi_callback_info info)496 napi_value AudioHapticManagerNapi::SetAudioLatencyMode(napi_env env, napi_callback_info info)
497 {
498 napi_value result = nullptr;
499
500 size_t argc = ARGS_TWO;
501 napi_value argv[ARGS_TWO] = {0};
502 napi_value thisVar = nullptr;
503 void *data;
504 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
505 if (argc != ARGS_TWO) {
506 MEDIA_LOGE("SetAudioLatencyMode: requires 2 parameters");
507 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
508 return result;
509 }
510
511 void *native = nullptr;
512 napi_status status = napi_unwrap(env, thisVar, &native);
513 auto *audioHapticManagerNapi = reinterpret_cast<AudioHapticManagerNapi *>(native);
514 if (status != napi_ok || audioHapticManagerNapi == nullptr) {
515 MEDIA_LOGE("SetAudioLatencyMode: unwrap failure!");
516 return result;
517 }
518
519 napi_valuetype valueType = napi_undefined;
520 napi_typeof(env, argv[PARAM0], &valueType);
521 if (valueType != napi_number) {
522 MEDIA_LOGE("SetAudioLatencyMode: the param type mismatch");
523 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
524 return result;
525 }
526 int32_t sourceID = 0;
527 napi_get_value_int32(env, argv[PARAM0], &sourceID);
528
529 napi_typeof(env, argv[PARAM1], &valueType);
530 if (valueType != napi_number) {
531 MEDIA_LOGE("SetAudioLatencyMode: the param type mismatch");
532 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
533 return result;
534 }
535 int32_t latencyMode = 0;
536 napi_get_value_int32(env, argv[PARAM1], &latencyMode);
537 if (!IsLegalAudioLatencyMode (latencyMode)) {
538 MEDIA_LOGE("SetAudioLatencyMode: the value of latencyMode is invalid");
539 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID);
540 return result;
541 }
542
543 int32_t setResult = audioHapticManagerNapi->audioHapticMgrClient_->
544 SetAudioLatencyMode(sourceID, static_cast<AudioLatencyMode>(latencyMode));
545 if (setResult != SUCCESS) {
546 MEDIA_LOGE("SetAudioLatencyMode: Failed to set audio latency mode");
547 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_OPERATE_NOT_ALLOWED);
548 }
549 return result;
550 }
551
IsLegalAudioLatencyMode(int32_t latencyMode)552 bool AudioHapticManagerNapi::IsLegalAudioLatencyMode(int32_t latencyMode)
553 {
554 switch (latencyMode) {
555 case AUDIO_LATENCY_MODE_NORMAL:
556 case AUDIO_LATENCY_MODE_FAST:
557 return true;
558 default:
559 break;
560 }
561 MEDIA_LOGE("IsLegalAudioLatencyMode: latencyMode %{public}d is invalid", latencyMode);
562 return false;
563 }
564
SetStreamUsage(napi_env env,napi_callback_info info)565 napi_value AudioHapticManagerNapi::SetStreamUsage(napi_env env, napi_callback_info info)
566 {
567 napi_value result = nullptr;
568
569 size_t argc = ARGS_TWO;
570 napi_value argv[ARGS_TWO] = {0};
571 napi_value thisVar = nullptr;
572 void *data;
573 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
574 if (argc != ARGS_TWO) {
575 MEDIA_LOGE("SetStreamUsage: requires 2 parameters");
576 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified");
577 return result;
578 }
579
580 void *native = nullptr;
581 napi_status status = napi_unwrap(env, thisVar, &native);
582 auto *audioHapticManagerNapi = reinterpret_cast<AudioHapticManagerNapi *>(native);
583 if (status != napi_ok || audioHapticManagerNapi == nullptr) {
584 MEDIA_LOGE("SetStreamUsage: unwrap failure!");
585 return result;
586 }
587
588 napi_valuetype valueType = napi_undefined;
589 napi_typeof(env, argv[PARAM0], &valueType);
590 if (valueType != napi_number) {
591 MEDIA_LOGE("SetStreamUsage: the param type mismatch");
592 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "the type of id must be number");
593 return result;
594 }
595 int32_t sourceID = 0;
596 napi_get_value_int32(env, argv[PARAM0], &sourceID);
597
598 napi_typeof(env, argv[PARAM1], &valueType);
599 if (valueType != napi_number) {
600 MEDIA_LOGE("SetStreamUsage: the param type mismatch");
601 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "the type of usage must be number");
602 return result;
603 }
604 int32_t streamUsage = 0;
605 napi_get_value_int32(env, argv[PARAM1], &streamUsage);
606 if (!IsLegalAudioStreamUsage (streamUsage)) {
607 MEDIA_LOGE("SetStreamUsage: the value of streamUsage is invalid");
608 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID,
609 "the param of usage must be enum audio.StreamUsage");
610 return result;
611 }
612
613 int32_t setResult = audioHapticManagerNapi->audioHapticMgrClient_->
614 SetStreamUsage(sourceID, static_cast<AudioStandard::StreamUsage>(streamUsage));
615 if (setResult != SUCCESS) {
616 MEDIA_LOGE("SetStreamUsage: Failed to set audio stream usage");
617 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_OPERATE_NOT_ALLOWED);
618 }
619 return result;
620 }
621
IsLegalAudioStreamUsage(int32_t streamUsage)622 bool AudioHapticManagerNapi::IsLegalAudioStreamUsage(int32_t streamUsage)
623 {
624 switch (streamUsage) {
625 case AudioStandard::STREAM_USAGE_MUSIC:
626 case AudioStandard::STREAM_USAGE_VOICE_COMMUNICATION:
627 case AudioStandard::STREAM_USAGE_VOICE_ASSISTANT:
628 case AudioStandard::STREAM_USAGE_ALARM:
629 case AudioStandard::STREAM_USAGE_VOICE_MESSAGE:
630 case AudioStandard::STREAM_USAGE_RINGTONE:
631 case AudioStandard::STREAM_USAGE_NOTIFICATION:
632 case AudioStandard::STREAM_USAGE_ACCESSIBILITY:
633 case AudioStandard::STREAM_USAGE_SYSTEM:
634 case AudioStandard::STREAM_USAGE_MOVIE:
635 case AudioStandard::STREAM_USAGE_GAME:
636 case AudioStandard::STREAM_USAGE_AUDIOBOOK:
637 case AudioStandard::STREAM_USAGE_NAVIGATION:
638 case AudioStandard::STREAM_USAGE_DTMF:
639 case AudioStandard::STREAM_USAGE_ENFORCED_TONE:
640 return true;
641 default:
642 break;
643 }
644 MEDIA_LOGE("IsLegalAudioStreamUsage: streamUsage %{public}d is invalid", streamUsage);
645 return false;
646 }
647
CreatePlayer(napi_env env,napi_callback_info info)648 napi_value AudioHapticManagerNapi::CreatePlayer(napi_env env, napi_callback_info info)
649 {
650 napi_value result = nullptr;
651 napi_value property = nullptr;
652 napi_value resource = nullptr;
653 size_t argc = ARGS_TWO;
654 napi_value argv[ARGS_TWO] = {0};
655 napi_value thisVar = nullptr;
656
657 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
658 napi_get_undefined(env, &result);
659 CHECK_AND_RETURN_RET_LOG((status == napi_ok && thisVar != nullptr), result, "napi_get_cb_info failed");
660 if (argc != ARGS_ONE && argc != ARGS_TWO) {
661 MEDIA_LOGE("CreatePlayer: requires 1 parameter or 2 parameters");
662 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified");
663 return result;
664 }
665
666 std::unique_ptr<AudioHapticManagerAsyncContext> asyncContext = std::make_unique<AudioHapticManagerAsyncContext>();
667 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
668 CHECK_AND_RETURN_RET_LOG(status == napi_ok && asyncContext->objectInfo != nullptr, result, "objectInfo invalid");
669
670 for (size_t i = PARAM0; i < argc; i++) {
671 napi_valuetype valueType = napi_undefined;
672 napi_typeof(env, argv[i], &valueType);
673 if (i == PARAM0 && valueType == napi_number) {
674 napi_get_value_int32(env, argv[i], &asyncContext->sourceID);
675 } else if (i == PARAM1 && valueType == napi_object) {
676 if (napi_get_named_property(env, argv[PARAM1], "muteAudio", &property) == napi_ok) {
677 napi_get_value_bool(env, property, &(asyncContext->playerOptions.muteAudio));
678 }
679 if (napi_get_named_property(env, argv[PARAM1], "muteHaptics", &property) == napi_ok) {
680 napi_get_value_bool(env, property, &(asyncContext->playerOptions.muteHaptics));
681 }
682 } else {
683 MEDIA_LOGE("CreatePlayer: the param type mismatch");
684 AudioHapticCommonNapi::ThrowError(env, NAPI_ERR_INPUT_INVALID,
685 "incorrect parameter types: The type of id must be number; The type of options must be object");
686 return result;
687 }
688 }
689 napi_create_promise(env, &asyncContext->deferred, &result);
690
691 napi_create_string_utf8(env, "CreatePlayer", NAPI_AUTO_LENGTH, &resource);
692 status = napi_create_async_work(env, nullptr, resource, AsyncCreatePlayer,
693 CreatePlayerAsyncCallbackComp, static_cast<void*>(asyncContext.get()), &asyncContext->work);
694 if (status != napi_ok) {
695 MEDIA_LOGE("CreatePlayer: Failed to get create async work");
696 napi_get_undefined(env, &result);
697 } else {
698 napi_queue_async_work(env, asyncContext->work);
699 asyncContext.release();
700 }
701
702 return result;
703 }
704
AsyncCreatePlayer(napi_env env,void * data)705 void AudioHapticManagerNapi::AsyncCreatePlayer(napi_env env, void *data)
706 {
707 AudioHapticManagerAsyncContext *context = static_cast<AudioHapticManagerAsyncContext *>(data);
708 std::shared_ptr<AudioHapticPlayer> audioHapticPlayer =
709 context->objectInfo->audioHapticMgrClient_->CreatePlayer(context->sourceID, context->playerOptions);
710 if (audioHapticPlayer != nullptr) {
711 int32_t result = audioHapticPlayer->Prepare();
712 if (result == MSERR_OK) {
713 context->audioHapticPlayer = audioHapticPlayer;
714 context->status = SUCCESS;
715 return;
716 }
717 // Fail to prepare the audio haptic player. Throw err.
718 if (result == MSERR_OPEN_FILE_FAILED) {
719 context->errCode = NAPI_ERR_IO_ERROR;
720 } else if (result == MSERR_UNSUPPORT_FILE) {
721 context->errCode = NAPI_ERR_UNSUPPORTED_FORMAT;
722 } else {
723 context->errCode = NAPI_ERR_OPERATE_NOT_ALLOWED;
724 }
725 } else {
726 context->errCode = NAPI_ERR_OPERATE_NOT_ALLOWED;
727 }
728 context->audioHapticPlayer = nullptr;
729 context->status = ERROR;
730 context->errMessage = AudioHapticCommonNapi::GetMessageByCode(context->errCode);
731 }
732
CreatePlayerAsyncCallbackComp(napi_env env,napi_status status,void * data)733 void AudioHapticManagerNapi::CreatePlayerAsyncCallbackComp(napi_env env, napi_status status, void *data)
734 {
735 auto context = static_cast<AudioHapticManagerAsyncContext *>(data);
736 napi_value result[2] = {};
737 napi_value playerResult = nullptr;
738
739 if (context->audioHapticPlayer != nullptr) {
740 playerResult = AudioHapticPlayerNapi::CreatePlayerInstance(env, context->audioHapticPlayer);
741 if (playerResult == nullptr) {
742 napi_value message = nullptr;
743 napi_create_string_utf8(env, "CreatePlayer Error: Operation is not supported or failed",
744 NAPI_AUTO_LENGTH, &message);
745 napi_create_error(env, nullptr, message, &result[PARAM0]);
746 napi_get_undefined(env, &result[PARAM1]);
747 } else {
748 napi_get_undefined(env, &result[PARAM0]);
749 result[PARAM1] = playerResult;
750 }
751 } else {
752 MEDIA_LOGE("CreatePlayer: Failed to create audio haptic player!");
753 napi_value message = nullptr;
754 napi_value code = nullptr;
755 napi_create_string_utf8(env, context->errMessage.c_str(), NAPI_AUTO_LENGTH, &message);
756 napi_create_error(env, nullptr, message, &result[PARAM0]);
757 napi_create_int32(env, context->errCode, &code);
758 napi_set_named_property(env, result[PARAM0], "code", code);
759 napi_get_undefined(env, &result[PARAM1]);
760 }
761
762 if (context->deferred) {
763 if (context->status == SUCCESS) {
764 napi_resolve_deferred(env, context->deferred, result[PARAM1]);
765 } else {
766 napi_reject_deferred(env, context->deferred, result[PARAM0]);
767 }
768 }
769 napi_delete_async_work(env, context->work);
770
771 delete context;
772 context = nullptr;
773 }
774
Init(napi_env env,napi_value exports)775 static napi_value Init(napi_env env, napi_value exports)
776 {
777 AudioHapticManagerNapi::Init(env, exports);
778 AudioHapticPlayerNapi::Init(env, exports);
779 AudioHapticPlayerOptionsNapi::Init(env, exports);
780
781 return exports;
782 }
783
784 /*
785 * module define
786 */
787 static napi_module g_module = {
788 .nm_version = 1,
789 .nm_flags = 0,
790 .nm_filename = nullptr,
791 .nm_register_func = Init,
792 .nm_modname = "multimedia.audioHaptic",
793 .nm_priv = (reinterpret_cast<void*>(0)),
794 .reserved = {0}
795 };
796
797 /*
798 * module register
799 */
RegisterModule(void)800 extern "C" __attribute__((constructor)) void RegisterModule(void)
801 {
802 napi_module_register(&g_module);
803 }
804 } // namespace Media
805 } // namespace OHOS