• 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_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