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 "ringtone_player_napi.h"
17 
18 #include "audio_renderer_info_napi.h"
19 #include "avplayer_napi.h"
20 #include "system_sound_log.h"
21 
22 using namespace std;
23 
24 namespace {
25 /* Constants for array index */
26 const int32_t PARAM0 = 0;
27 const int32_t PARAM1 = 1;
28 
29 /* Constants for array size */
30 const int32_t ARGS_ONE = 1;
31 const int32_t ARGS_TWO = 2;
32 
33 const std::string AUDIO_INTERRUPT_CALLBACK_NAME = "audioInterrupt";
34 
35 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "RingtonePlayerNapi"};
36 
37 const int SUCCESS = 0;
38 }
39 
40 namespace OHOS {
41 namespace Media {
42 static const std::map<RingtoneState, std::string> STATEMAP = {
43     {STATE_INVALID, AVPlayerState::STATE_ERROR},
44     {STATE_NEW, AVPlayerState::STATE_INITIALIZED},
45     {STATE_PREPARED, AVPlayerState::STATE_PREPARED},
46     {STATE_RUNNING, AVPlayerState::STATE_PLAYING},
47     {STATE_STOPPED, AVPlayerState::STATE_STOPPED},
48     {STATE_RELEASED, AVPlayerState::STATE_RELEASED},
49     {STATE_PAUSED, AVPlayerState::STATE_PAUSED},
50 };
51 
52 thread_local napi_ref RingtonePlayerNapi::sConstructor_ = nullptr;
53 shared_ptr<RingtonePlayer> RingtonePlayerNapi::sRingtonePlayer_ = nullptr;
54 
RingtonePlayerNapi()55 RingtonePlayerNapi::RingtonePlayerNapi() : env_(nullptr) {}
56 
57 RingtonePlayerNapi::~RingtonePlayerNapi() = default;
58 
ThrowErrorAndReturn(napi_env env,int32_t errCode,const std::string & errMessage)59 static napi_value ThrowErrorAndReturn(napi_env env, int32_t errCode, const std::string &errMessage)
60 {
61     RingtoneCommonNapi::ThrowError(env, errCode, errMessage);
62     return nullptr;
63 }
64 
Init(napi_env env,napi_value exports)65 napi_value RingtonePlayerNapi::Init(napi_env env, napi_value exports)
66 {
67     napi_status status;
68     napi_value ctorObj;
69     int32_t refCount = 1;
70 
71     napi_property_descriptor ringtone_player_prop[] = {
72         DECLARE_NAPI_FUNCTION("getTitle", GetTitle),
73         DECLARE_NAPI_FUNCTION("getAudioRendererInfo", GetAudioRendererInfo),
74         DECLARE_NAPI_FUNCTION("configure", Configure),
75         DECLARE_NAPI_FUNCTION("start", Start),
76         DECLARE_NAPI_FUNCTION("stop", Stop),
77         DECLARE_NAPI_FUNCTION("release", Release),
78         DECLARE_NAPI_FUNCTION("on", On),
79         DECLARE_NAPI_FUNCTION("off", Off),
80         DECLARE_NAPI_GETTER("state", GetAudioState)
81     };
82 
83     status = napi_define_class(env, RINGTONE_PLAYER_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
84         RingtonePlayerNapiConstructor, nullptr, sizeof(ringtone_player_prop) / sizeof(ringtone_player_prop[0]),
85         ringtone_player_prop, &ctorObj);
86     if (status == napi_ok) {
87         if (napi_create_reference(env, ctorObj, refCount, &sConstructor_) == napi_ok) {
88             status = napi_set_named_property(env, exports, RINGTONE_PLAYER_NAPI_CLASS_NAME.c_str(), ctorObj);
89             if (status == napi_ok) {
90                 return exports;
91             }
92         }
93     }
94 
95     return nullptr;
96 }
97 
RingtonePlayerNapiConstructor(napi_env env,napi_callback_info info)98 napi_value RingtonePlayerNapi::RingtonePlayerNapiConstructor(napi_env env, napi_callback_info info)
99 {
100     napi_status status;
101     napi_value result = nullptr;
102     napi_value thisVar = nullptr;
103 
104     napi_get_undefined(env, &result);
105     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
106     if (status == napi_ok && thisVar != nullptr) {
107         std::unique_ptr<RingtonePlayerNapi> obj = std::make_unique<RingtonePlayerNapi>();
108         if (obj != nullptr) {
109             obj->env_ = env;
110             if (obj->sRingtonePlayer_ != nullptr) {
111                 obj->ringtonePlayer_ = move(obj->sRingtonePlayer_);
112             } else {
113                 MEDIA_LOGE("Failed to create sRingtonePlayer_ instance.");
114                 return result;
115             }
116 
117             if (obj->ringtonePlayer_ != nullptr && obj->callbackNapi_ == nullptr) {
118                 obj->callbackNapi_ = std::make_shared<RingtonePlayerCallbackNapi>(env);
119                 CHECK_AND_RETURN_RET_LOG(obj->callbackNapi_ != nullptr, result, "No memory");
120                 int32_t ret = obj->ringtonePlayer_->SetRingtonePlayerInterruptCallback(obj->callbackNapi_);
121                 MEDIA_LOGI("AudioRendererNapi::Construct SetRendererCallback %{public}s",
122                     ret == 0 ? "succeess" : "failed");
123             }
124 
125             status = napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()),
126                 RingtonePlayerNapi::RingtonePlayerNapiDestructor, nullptr, nullptr);
127             if (status == napi_ok) {
128                 obj.release();
129                 return thisVar;
130             } else {
131                 MEDIA_LOGE("Failed to wrap the native rngplyrmngr object with JS.");
132             }
133         }
134     }
135 
136     return result;
137 }
138 
RingtonePlayerNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)139 void RingtonePlayerNapi::RingtonePlayerNapiDestructor(napi_env env, void* nativeObject, void* finalize_hint)
140 {
141     RingtonePlayerNapi *ringtonePlayerHelper = reinterpret_cast<RingtonePlayerNapi*>(nativeObject);
142     if (ringtonePlayerHelper != nullptr) {
143         ringtonePlayerHelper->~RingtonePlayerNapi();
144     }
145 }
146 
GetRingtonePlayerInstance(napi_env env,shared_ptr<RingtonePlayer> & ringtonePlayer)147 napi_value RingtonePlayerNapi::GetRingtonePlayerInstance(napi_env env, shared_ptr<RingtonePlayer> &ringtonePlayer)
148 {
149     napi_status status;
150     napi_value result = nullptr;
151     napi_value ctor;
152 
153     status = napi_get_reference_value(env, sConstructor_, &ctor);
154     if (status == napi_ok) {
155         sRingtonePlayer_ = ringtonePlayer;
156         status = napi_new_instance(env, ctor, 0, nullptr, &result);
157         if (status == napi_ok) {
158             return result;
159         } else {
160             MEDIA_LOGE("GetRingtonePlayerInstance: New instance could not be obtained.");
161         }
162     }
163 
164     napi_get_undefined(env, &result);
165     return result;
166 }
167 
CommonAsyncCallbackComplete(napi_env env,napi_status status,void * data)168 void RingtonePlayerNapi::CommonAsyncCallbackComplete(napi_env env, napi_status status, void* data)
169 {
170     auto context = static_cast<RingtonePlayerAsyncContext *>(data);
171     napi_value callback = nullptr;
172     napi_value retVal = nullptr;
173     napi_value result[2] = {};
174 
175     napi_get_undefined(env, &result[PARAM1]);
176     if (!context->status) {
177         napi_get_undefined(env, &result[PARAM0]);
178     } else {
179         napi_value message = nullptr;
180         napi_create_string_utf8(env, "Error: Operation is not supported or failed", NAPI_AUTO_LENGTH, &message);
181         napi_create_error(env, nullptr, message, &result[PARAM0]);
182     }
183 
184     if (context->deferred) {
185         if (!context->status) {
186             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
187         } else {
188             napi_reject_deferred(env, context->deferred, result[PARAM0]);
189         }
190     } else {
191         napi_get_reference_value(env, context->callbackRef, &callback);
192         napi_call_function(env, nullptr, callback, ARGS_TWO, result, &retVal);
193         napi_delete_reference(env, context->callbackRef);
194     }
195     napi_delete_async_work(env, context->work);
196 
197     delete context;
198     context = nullptr;
199 }
200 
GetTitleAsyncCallbackComplete(napi_env env,napi_status status,void * data)201 void RingtonePlayerNapi::GetTitleAsyncCallbackComplete(napi_env env, napi_status status, void *data)
202 {
203     auto context = static_cast<RingtonePlayerAsyncContext *>(data);
204     napi_value getTitleCallback = nullptr;
205     napi_value retVal = nullptr;
206     napi_value result[2] = {};
207 
208     if (!context->status) {
209         napi_get_undefined(env, &result[PARAM0]);
210         napi_create_string_utf8(env, context->title.c_str(), NAPI_AUTO_LENGTH, &result[PARAM1]);
211     } else {
212         napi_value message = nullptr;
213         napi_create_string_utf8(env, "GetTitle Error: Operation is not supported or failed",
214             NAPI_AUTO_LENGTH, &message);
215         napi_create_error(env, nullptr, message, &result[PARAM0]);
216         napi_get_undefined(env, &result[PARAM1]);
217     }
218 
219     if (context->deferred) {
220         if (!context->status) {
221             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
222         } else {
223             napi_reject_deferred(env, context->deferred, result[PARAM0]);
224         }
225     } else {
226         napi_get_reference_value(env, context->callbackRef, &getTitleCallback);
227         napi_call_function(env, nullptr, getTitleCallback, ARGS_TWO, result, &retVal);
228         napi_delete_reference(env, context->callbackRef);
229     }
230     napi_delete_async_work(env, context->work);
231 
232     delete context;
233     context = nullptr;
234 }
235 
GetTitle(napi_env env,napi_callback_info info)236 napi_value RingtonePlayerNapi::GetTitle(napi_env env, napi_callback_info info)
237 {
238     napi_status status;
239     napi_value result = nullptr;
240     napi_value resource = nullptr;
241     size_t argc = ARGS_ONE;
242     napi_value argv[ARGS_ONE] = {0};
243     napi_value thisVar = nullptr;
244     const int32_t refCount = 1;
245 
246     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
247     napi_get_undefined(env, &result);
248     if (status != napi_ok || thisVar == nullptr) {
249         MEDIA_LOGE("GetTitle: Failed to retrieve details about the callback");
250         return result;
251     }
252 
253     NAPI_ASSERT(env, argc <= ARGS_ONE, "GetTitle: requires 1 parameter maximum");
254     std::unique_ptr<RingtonePlayerAsyncContext> asyncContext = std::make_unique<RingtonePlayerAsyncContext>();
255     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
256     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
257         if (argc == ARGS_ONE) {
258             napi_valuetype valueType = napi_undefined;
259             napi_typeof(env, argv[PARAM0], &valueType);
260             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
261                 "GetTitle: the param type is not napi_function");
262             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
263         } else {
264             napi_create_promise(env, &asyncContext->deferred, &result);
265         }
266 
267         napi_create_string_utf8(env, "GetTitle", NAPI_AUTO_LENGTH, &resource);
268         status = napi_create_async_work(env, nullptr, resource,
269             [](napi_env env, void *data) {
270                 RingtonePlayerAsyncContext *context = static_cast<RingtonePlayerAsyncContext *>(data);
271                 context->title = context->objectInfo->ringtonePlayer_->GetTitle();
272                 context->status = SUCCESS;
273             },
274             GetTitleAsyncCallbackComplete, static_cast<void *>(asyncContext.get()), &asyncContext->work);
275         if (status != napi_ok) {
276             MEDIA_LOGE("GetTitle: Failed to get create async work");
277             napi_get_undefined(env, &result);
278         } else {
279             napi_queue_async_work(env, asyncContext->work);
280             asyncContext.release();
281         }
282     }
283 
284     return result;
285 }
286 
GetAudioRendererInfoAsyncCallbackComplete(napi_env env,napi_status status,void * data)287 void RingtonePlayerNapi::GetAudioRendererInfoAsyncCallbackComplete(napi_env env, napi_status status, void *data)
288 {
289     auto context = static_cast<RingtonePlayerAsyncContext *>(data);
290     napi_value getRendererInfoCallback = nullptr;
291     napi_value retVal = nullptr;
292     napi_value valueParam = nullptr;
293     napi_value result[2] = {};
294 
295     if (!context->status) {
296         unique_ptr<AudioStandard::AudioRendererInfo> audioRendererInfo =
297             make_unique<AudioStandard::AudioRendererInfo>();
298         audioRendererInfo->contentType = context->contentType;
299         audioRendererInfo->streamUsage = context->streamUsage;
300         audioRendererInfo->rendererFlags = context->rendererFlags;
301 
302         valueParam = AudioRendererInfoNapi::CreateAudioRendererInfoWrapper(env, audioRendererInfo);
303         napi_get_undefined(env, &result[PARAM0]);
304         result[PARAM1] = valueParam;
305     } else {
306         napi_value message = nullptr;
307         napi_create_string_utf8(env, "GetRendererInfo Error: Operation is not supported or failed",
308             NAPI_AUTO_LENGTH, &message);
309         napi_create_error(env, nullptr, message, &result[PARAM0]);
310         napi_get_undefined(env, &result[PARAM1]);
311     }
312 
313     if (context->deferred) {
314         if (!context->status) {
315             napi_resolve_deferred(env, context->deferred, result[PARAM1]);
316         } else {
317             napi_reject_deferred(env, context->deferred, result[PARAM0]);
318         }
319     } else {
320         napi_get_reference_value(env, context->callbackRef, &getRendererInfoCallback);
321         napi_call_function(env, nullptr, getRendererInfoCallback, ARGS_TWO, result, &retVal);
322         napi_delete_reference(env, context->callbackRef);
323     }
324     napi_delete_async_work(env, context->work);
325 
326     delete context;
327     context = nullptr;
328 }
329 
GetAudioRendererInfo(napi_env env,napi_callback_info info)330 napi_value RingtonePlayerNapi::GetAudioRendererInfo(napi_env env, napi_callback_info info)
331 {
332     napi_status status;
333     napi_value result = nullptr;
334     napi_value resource = nullptr;
335     size_t argc = ARGS_ONE;
336     napi_value argv[ARGS_ONE] = {0};
337     napi_value thisVar = nullptr;
338     const int32_t refCount = 1;
339 
340     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
341     napi_get_undefined(env, &result);
342     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result,
343         "GetAudioRendererInfo: Failed to retrieve details about the callback");
344 
345     NAPI_ASSERT(env, argc <= ARGS_ONE, "GetAudioRendererInfo: requires 1 parameter maximum");
346     std::unique_ptr<RingtonePlayerAsyncContext> asyncContext = std::make_unique<RingtonePlayerAsyncContext>();
347     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
348     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
349         if (argc == ARGS_ONE) {
350             napi_valuetype valueType = napi_undefined;
351             napi_typeof(env, argv[PARAM0], &valueType);
352             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
353                 "GetAudioRendererInfo: the param type is not napi_function");
354             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
355         } else {
356             napi_create_promise(env, &asyncContext->deferred, &result);
357         }
358 
359         napi_create_string_utf8(env, "GetAudioRendererInfo", NAPI_AUTO_LENGTH, &resource);
360         status = napi_create_async_work(env, nullptr, resource, AsyncGetAudioRendererInfo,
361             GetAudioRendererInfoAsyncCallbackComplete, static_cast<void *>(asyncContext.get()), &asyncContext->work);
362         if (status != napi_ok) {
363             MEDIA_LOGE("GetAudioRendererInfo: Failed to get create async work");
364             napi_get_undefined(env, &result);
365         } else {
366             napi_queue_async_work(env, asyncContext->work);
367             asyncContext.release();
368         }
369     }
370 
371     return result;
372 }
373 
AsyncGetAudioRendererInfo(napi_env env,void * data)374 void RingtonePlayerNapi::AsyncGetAudioRendererInfo(napi_env env, void *data)
375 {
376     RingtonePlayerAsyncContext *context = static_cast<RingtonePlayerAsyncContext *>(data);
377     AudioStandard::AudioRendererInfo rendererInfo;
378     context->status = context->objectInfo->ringtonePlayer_->GetAudioRendererInfo(rendererInfo);
379     if (context->status == SUCCESS) {
380         context->contentType = rendererInfo.contentType;
381         context->streamUsage = rendererInfo.streamUsage;
382         context->rendererFlags  = rendererInfo.rendererFlags;
383     }
384 }
385 
Configure(napi_env env,napi_callback_info info)386 napi_value RingtonePlayerNapi::Configure(napi_env env, napi_callback_info info)
387 {
388     napi_value result = nullptr;
389     napi_value resource = nullptr;
390     napi_value property = nullptr;
391     size_t argc = ARGS_TWO;
392     napi_value argv[ARGS_TWO] = {0};
393     napi_value thisVar = nullptr;
394     const int32_t refCount = 1;
395     double volume = 1.0;
396 
397     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
398     napi_get_undefined(env, &result);
399     CHECK_AND_RETURN_RET_LOG(status == napi_ok && thisVar != nullptr, result, "Configure: napi_get_cb_info failed");
400 
401     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
402     std::unique_ptr<RingtonePlayerAsyncContext> asyncContext = std::make_unique<RingtonePlayerAsyncContext>();
403     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
404     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
405         napi_valuetype valueType = napi_undefined;
406         napi_typeof(env, argv[PARAM0], &valueType);
407         if (valueType == napi_object) {
408             if ((napi_get_named_property(env, argv[PARAM0], "volume", &property) != napi_ok)
409                 || napi_get_value_double(env, property, &volume) != napi_ok) {
410                 NAPI_ASSERT(env, false, "missing volume properties");
411             }
412             asyncContext->volume = (float)volume;
413 
414             if ((napi_get_named_property(env, argv[PARAM0], "loop", &property) != napi_ok)
415                 || napi_get_value_bool(env, property, &asyncContext->loop) != napi_ok) {
416                 NAPI_ASSERT(env, false, "missing loop properties");
417             }
418         }
419 
420         if (argc == ARGS_TWO) {
421             napi_typeof(env, argv[PARAM1], &valueType);
422             if (valueType == napi_function) {
423                 napi_create_reference(env, argv[PARAM1], refCount, &asyncContext->callbackRef);
424             }
425         } else {
426             napi_create_promise(env, &asyncContext->deferred, &result);
427         }
428 
429         napi_create_string_utf8(env, "Configure", NAPI_AUTO_LENGTH, &resource);
430         status = napi_create_async_work(env, nullptr, resource, AsyncConfigure,
431             CommonAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
432         if (status != napi_ok) {
433             MEDIA_LOGE("Configure: Failed to create async work");
434             napi_get_undefined(env, &result);
435         } else {
436             napi_queue_async_work(env, asyncContext->work);
437             asyncContext.release();
438         }
439     }
440 
441     return result;
442 }
443 
AsyncConfigure(napi_env env,void * data)444 void RingtonePlayerNapi::AsyncConfigure(napi_env env, void *data)
445 {
446     RingtonePlayerAsyncContext* context = static_cast<RingtonePlayerAsyncContext*>(data);
447     context->status = context->objectInfo->ringtonePlayer_->Configure(context->volume, context->loop);
448 }
449 
Start(napi_env env,napi_callback_info info)450 napi_value RingtonePlayerNapi::Start(napi_env env, napi_callback_info info)
451 {
452     napi_status status;
453     napi_value result = nullptr;
454     napi_value resource = nullptr;
455     size_t argc = ARGS_ONE;
456     napi_value argv[ARGS_ONE] = {0};
457     napi_value thisVar = nullptr;
458     const int32_t refCount = 1;
459 
460     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
461     napi_get_undefined(env, &result);
462     if (status != napi_ok || thisVar == nullptr) {
463         MEDIA_LOGE("Start: Failed to retrieve details about the callback");
464         return result;
465     }
466 
467     NAPI_ASSERT(env, argc <= ARGS_ONE, "Start: requires 1 parameter maximum");
468     std::unique_ptr<RingtonePlayerAsyncContext> asyncContext = std::make_unique<RingtonePlayerAsyncContext>();
469     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
470     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
471         if (argc == ARGS_ONE) {
472             napi_valuetype valueType = napi_undefined;
473             napi_typeof(env, argv[PARAM0], &valueType);
474             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
475                 "Start: the param type is not napi_function");
476             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
477         } else {
478             napi_create_promise(env, &asyncContext->deferred, &result);
479         }
480 
481         napi_create_string_utf8(env, "Start", NAPI_AUTO_LENGTH, &resource);
482         status = napi_create_async_work(env, nullptr, resource,
483             [](napi_env env, void* data) {
484                 RingtonePlayerAsyncContext* context = static_cast<RingtonePlayerAsyncContext*>(data);
485                 context->status = context->objectInfo->ringtonePlayer_->Start();
486             },
487             CommonAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
488         if (status != napi_ok) {
489             MEDIA_LOGE("Start: Failed to get create async work");
490             napi_get_undefined(env, &result);
491         } else {
492             napi_queue_async_work(env, asyncContext->work);
493             asyncContext.release();
494         }
495     }
496 
497     return result;
498 }
499 
Stop(napi_env env,napi_callback_info info)500 napi_value RingtonePlayerNapi::Stop(napi_env env, napi_callback_info info)
501 {
502     napi_status status;
503     napi_value result = nullptr;
504     napi_value resource = nullptr;
505     size_t argc = ARGS_ONE;
506     napi_value argv[ARGS_ONE] = {0};
507     napi_value thisVar = nullptr;
508     const int32_t refCount = 1;
509 
510     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
511     napi_get_undefined(env, &result);
512     if (status != napi_ok || thisVar == nullptr) {
513         MEDIA_LOGE("Stop: Failed to retrieve details about the callback");
514         return result;
515     }
516 
517     NAPI_ASSERT(env, argc <= ARGS_ONE, "Stop: requires 1 parameter maximum");
518     std::unique_ptr<RingtonePlayerAsyncContext> asyncContext = std::make_unique<RingtonePlayerAsyncContext>();
519     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
520     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
521         if (argc == ARGS_ONE) {
522             napi_valuetype valueType = napi_undefined;
523             napi_typeof(env, argv[PARAM0], &valueType);
524             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
525                 "Stop: the param type is not napi_function");
526             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
527         } else {
528             napi_create_promise(env, &asyncContext->deferred, &result);
529         }
530 
531         napi_create_string_utf8(env, "Stop", NAPI_AUTO_LENGTH, &resource);
532         status = napi_create_async_work(env, nullptr, resource,
533             [](napi_env env, void* data) {
534                 RingtonePlayerAsyncContext* context = static_cast<RingtonePlayerAsyncContext*>(data);
535                 context->status = context->objectInfo->ringtonePlayer_->Stop();
536             },
537             CommonAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
538         if (status != napi_ok) {
539             MEDIA_LOGE("Stop: Failed to get create async work");
540             napi_get_undefined(env, &result);
541         } else {
542             napi_queue_async_work(env, asyncContext->work);
543             asyncContext.release();
544         }
545     }
546 
547     return result;
548 }
549 
Release(napi_env env,napi_callback_info info)550 napi_value RingtonePlayerNapi::Release(napi_env env, napi_callback_info info)
551 {
552     napi_status status;
553     napi_value result = nullptr;
554     napi_value resource = nullptr;
555     size_t argc = ARGS_ONE;
556     napi_value argv[ARGS_ONE] = {0};
557     napi_value thisVar = nullptr;
558     const int32_t refCount = 1;
559 
560     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
561     napi_get_undefined(env, &result);
562     if (status != napi_ok || thisVar == nullptr) {
563         MEDIA_LOGE("Release: Failed to retrieve details about the callback");
564         return result;
565     }
566 
567     NAPI_ASSERT(env, argc <= ARGS_ONE, "Release: requires 1 parameter maximum");
568     std::unique_ptr<RingtonePlayerAsyncContext> asyncContext = std::make_unique<RingtonePlayerAsyncContext>();
569     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
570     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
571         if (argc == ARGS_ONE) {
572             napi_valuetype valueType = napi_undefined;
573             napi_typeof(env, argv[PARAM0], &valueType);
574             CHECK_AND_RETURN_RET_LOG(valueType == napi_function, result,
575                 "Release: the param type is not napi_function");
576             napi_create_reference(env, argv[PARAM0], refCount, &asyncContext->callbackRef);
577         } else {
578             napi_create_promise(env, &asyncContext->deferred, &result);
579         }
580 
581         napi_create_string_utf8(env, "Release", NAPI_AUTO_LENGTH, &resource);
582         status = napi_create_async_work(env, nullptr, resource,
583             [](napi_env env, void* data) {
584                 RingtonePlayerAsyncContext* context = static_cast<RingtonePlayerAsyncContext*>(data);
585                 context->status = context->objectInfo->ringtonePlayer_->Release();
586             },
587             CommonAsyncCallbackComplete, static_cast<void*>(asyncContext.get()), &asyncContext->work);
588         if (status != napi_ok) {
589             MEDIA_LOGE("Release: Failed to get create async work");
590             napi_get_undefined(env, &result);
591         } else {
592             napi_queue_async_work(env, asyncContext->work);
593             asyncContext.release();
594         }
595     }
596 
597     return result;
598 }
599 
GetAudioState(napi_env env,napi_callback_info info)600 napi_value RingtonePlayerNapi::GetAudioState(napi_env env, napi_callback_info info)
601 {
602     napi_status status;
603     size_t argc = 0;
604     napi_value thisVar = nullptr;
605     napi_value result = nullptr;
606     napi_get_undefined(env, &result);
607 
608     status = napi_get_cb_info(env, info, &argc, nullptr, &thisVar, nullptr);
609     if (status != napi_ok || thisVar == nullptr) {
610         MEDIA_LOGE("GetAudioState: fail to napi_get_cb_info");
611         return result;
612     }
613 
614     std::string curState = AVPlayerState::STATE_ERROR;
615     std::unique_ptr<RingtonePlayerAsyncContext> asyncContext
616         = std::make_unique<RingtonePlayerAsyncContext>();
617     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->objectInfo));
618     if (status == napi_ok && asyncContext->objectInfo && asyncContext->objectInfo->ringtonePlayer_ != nullptr) {
619         RingtoneState ringtoneState_ = asyncContext->objectInfo->ringtonePlayer_->GetRingtoneState();
620         if (STATEMAP.find(ringtoneState_) != STATEMAP.end()) {
621             curState = STATEMAP.at(ringtoneState_);
622         }
623     }
624     napi_create_string_utf8(env, curState.c_str(), NAPI_AUTO_LENGTH, &result);
625 
626     return result;
627 }
628 
On(napi_env env,napi_callback_info info)629 napi_value RingtonePlayerNapi::On(napi_env env, napi_callback_info info)
630 {
631     const size_t requireArgc = 2;
632     size_t argc = 3;
633 
634     napi_value argv[requireArgc + 1] = {nullptr, nullptr, nullptr};
635     napi_value jsThis = nullptr;
636     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
637     if (status != napi_ok) {
638         ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM, "system err");
639     }
640     if (argc < requireArgc) {
641         ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified");
642     }
643 
644     napi_valuetype argvType = napi_undefined;
645     napi_typeof(env, argv[0], &argvType);
646     if (argvType != napi_string) {
647         ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID,
648             "incorrect parameter types: The type of eventType must be string");
649     }
650 
651     std::string callbackName = RingtoneCommonNapi::GetStringArgument(env, argv[0]);
652     MEDIA_LOGI("RingtonePlayerNapi: On callbackName: %{public}s", callbackName.c_str());
653 
654     napi_valuetype callbackFunction = napi_undefined;
655     if (argc == requireArgc) {
656         napi_typeof(env, argv[1], &callbackFunction);
657         if (callbackFunction != napi_function) {
658             ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID,
659                 "incorrect parameter types: The type of callback must be function");
660         }
661     } else {
662         napi_valuetype paramArg1 = napi_undefined;
663         napi_typeof(env, argv[1], &paramArg1);
664         napi_valuetype expectedValType = napi_number;  // Default. Reset it with 'callbackName' if check, if required.
665         if (paramArg1 != expectedValType) {
666             ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID,
667                 "incorrect parameter types: The parameter must be number");
668         }
669 
670         const int32_t arg2 = 2;
671         napi_typeof(env, argv[arg2], &callbackFunction);
672         if (callbackFunction != napi_function) {
673             ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID,
674                 "incorrect parameter types: The type of callback must be function");
675         }
676     }
677 
678     return RegisterCallback(env, jsThis, argv, callbackName);
679 }
680 
RegisterCallback(napi_env env,napi_value jsThis,napi_value * argv,const std::string & cbName)681 napi_value RingtonePlayerNapi::RegisterCallback(napi_env env, napi_value jsThis, napi_value* argv,
682     const std::string& cbName)
683 {
684     RingtonePlayerNapi *ringtonePlayerNapi = nullptr;
685     napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&ringtonePlayerNapi));
686     if (status != napi_ok) {
687         ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM, "system err");
688     }
689     if (ringtonePlayerNapi == nullptr) {
690         ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY, "no memory");
691     }
692     if (ringtonePlayerNapi->ringtonePlayer_ == nullptr) {
693         ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY, "no memory");
694     }
695 
696     napi_value result = nullptr;
697     napi_get_undefined(env, &result);
698 
699     if (!cbName.compare(AUDIO_INTERRUPT_CALLBACK_NAME)) {
700         result = RegisterRingtonePlayerCallback(env, argv, cbName, ringtonePlayerNapi);
701     } else {
702         bool unknownCallback = true;
703         if (unknownCallback) {
704             ThrowErrorAndReturn(env, NAPI_ERR_INVALID_PARAM,
705                 "parameter verification failed: The param of type is not supported");
706         }
707     }
708 
709     return result;
710 }
711 
RegisterRingtonePlayerCallback(napi_env env,napi_value * argv,const std::string & cbName,RingtonePlayerNapi * ringtonePlayerNapi)712 napi_value RingtonePlayerNapi::RegisterRingtonePlayerCallback(napi_env env, napi_value* argv,
713     const std::string& cbName, RingtonePlayerNapi *ringtonePlayerNapi)
714 {
715     if (ringtonePlayerNapi->callbackNapi_ == nullptr) {
716         ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY, "no memory");
717     }
718 
719     std::shared_ptr<RingtonePlayerCallbackNapi> cb =
720         std::static_pointer_cast<RingtonePlayerCallbackNapi>(ringtonePlayerNapi->callbackNapi_);
721     cb->SaveCallbackReference(cbName, argv[PARAM1]);
722 
723     napi_value result = nullptr;
724     napi_get_undefined(env, &result);
725     return result;
726 }
727 
Off(napi_env env,napi_callback_info info)728 napi_value RingtonePlayerNapi::Off(napi_env env, napi_callback_info info)
729 {
730     const size_t requireArgc = 2;
731     size_t argc = 3;
732 
733     napi_value argv[requireArgc + 1] = {nullptr, nullptr, nullptr};
734     napi_value jsThis = nullptr;
735     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
736     if (status != napi_ok) {
737         ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM, "system err");
738     }
739     if (argc > requireArgc) {
740         ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified");
741     }
742 
743     napi_valuetype callbackNameType = napi_undefined;
744     napi_typeof(env, argv[0], &callbackNameType);
745     if (callbackNameType != napi_string) {
746         ThrowErrorAndReturn(env, NAPI_ERR_INPUT_INVALID,
747             "incorrect parameter types: The type of eventType must be string");
748     }
749 
750     string callbackName = RingtoneCommonNapi::GetStringArgument(env, argv[0]);
751     MEDIA_LOGI("Off callbackName: %{public}s", callbackName.c_str());
752 
753     return UnregisterCallback(env, jsThis, callbackName);
754 }
755 
UnregisterCallback(napi_env env,napi_value jsThis,const string & cbName)756 napi_value RingtonePlayerNapi::UnregisterCallback(napi_env env, napi_value jsThis, const string& cbName)
757 {
758     RingtonePlayerNapi *ringtonePlayerNapi = nullptr;
759     napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&ringtonePlayerNapi));
760     if (status != napi_ok) {
761         ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM, "system err");
762     }
763     if (ringtonePlayerNapi == nullptr) {
764         ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY, "no memory");
765     }
766     if (ringtonePlayerNapi->ringtonePlayer_ == nullptr) {
767         ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY, "no memory");
768     }
769 
770     if (!cbName.compare(AUDIO_INTERRUPT_CALLBACK_NAME)) {
771         UnregisterRingtonePlayerCallback(ringtonePlayerNapi, cbName);
772     } else {
773         bool unknownCallback = true;
774         if (unknownCallback) {
775             ThrowErrorAndReturn(env, NAPI_ERR_INVALID_PARAM,
776                 "parameter verification failed: The param of type is not supported");
777         }
778     }
779 
780     napi_value result = nullptr;
781     napi_get_undefined(env, &result);
782     return result;
783 }
784 
UnregisterRingtonePlayerCallback(RingtonePlayerNapi * ringtonePlayerNapi,const string & cbName)785 void RingtonePlayerNapi::UnregisterRingtonePlayerCallback(RingtonePlayerNapi *ringtonePlayerNapi, const string& cbName)
786 {
787     CHECK_AND_RETURN_LOG(ringtonePlayerNapi->callbackNapi_ != nullptr, "ringtonePlayerCallbackNapi is nullptr");
788 
789     shared_ptr<RingtonePlayerCallbackNapi> cb =
790         static_pointer_cast<RingtonePlayerCallbackNapi>(ringtonePlayerNapi->callbackNapi_);
791     cb->RemoveCallbackReference(cbName);
792 }
793 } // namespace Media
794 } // namespace OHOS