• 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 #include "ringtone_player_callback_napi.h"
16 
17 #include <uv.h>
18 
19 #include "media_errors.h"
20 #include "media_log.h"
21 
22 using OHOS::HiviewDFX::HiLog;
23 using OHOS::HiviewDFX::HiLogLabel;
24 
25 namespace {
26     const std::string AUDIO_INTERRUPT_CALLBACK_NAME = "audioInterrupt";
27 
28     constexpr HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "RingtonePlayerCallbackNapi"};
29 }
30 
31 namespace OHOS {
32 namespace Media {
RingtonePlayerCallbackNapi(napi_env env)33 RingtonePlayerCallbackNapi::RingtonePlayerCallbackNapi(napi_env env)
34     : env_(env)
35 {
36     MEDIA_LOGI("RingtonePlayerCallbackNapi: instance create");
37 }
38 
~RingtonePlayerCallbackNapi()39 RingtonePlayerCallbackNapi::~RingtonePlayerCallbackNapi()
40 {
41     MEDIA_LOGI("RingtonePlayerCallbackNapi: instance destroy");
42 }
43 
SaveCallbackReference(const std::string & callbackName,napi_value args)44 void RingtonePlayerCallbackNapi::SaveCallbackReference(const std::string &callbackName, napi_value args)
45 {
46     std::lock_guard<std::mutex> lock(mutex_);
47     napi_ref callback = nullptr;
48     const int32_t refCount = 1;
49     napi_status status = napi_create_reference(env_, args, refCount, &callback);
50     CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
51                          "RingtonePlayerCallbackNapi: creating reference for callback fail");
52 
53     std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
54     if (callbackName == AUDIO_INTERRUPT_CALLBACK_NAME) {
55         interruptCallback_ = cb;
56     } else {
57         MEDIA_LOGE("RingtonePlayerCallbackNapi: Unknown callback type: %{public}s", callbackName.c_str());
58     }
59 }
60 
RemoveCallbackReference(const std::string & callbackName)61 void RingtonePlayerCallbackNapi::RemoveCallbackReference(const std::string &callbackName)
62 {
63     std::lock_guard<std::mutex> lock(mutex_);
64 
65     if (callbackName == AUDIO_INTERRUPT_CALLBACK_NAME) {
66         interruptCallback_ = nullptr;
67     } else {
68         MEDIA_LOGE("Unknown callback type: %{public}s", callbackName.c_str());
69     }
70 }
71 
SetValueInt32(const napi_env & env,const std::string & fieldStr,const int intValue,napi_value & result)72 static void SetValueInt32(const napi_env& env, const std::string& fieldStr, const int intValue, napi_value& result)
73 {
74     napi_handle_scope scope = nullptr;
75     napi_open_handle_scope(env, &scope);
76 
77     napi_value value = nullptr;
78     napi_create_int32(env, intValue, &value);
79     napi_set_named_property(env, result, fieldStr.c_str(), value);
80 
81     napi_close_handle_scope(env, scope);
82 }
83 
NativeInterruptEventToJsObj(const napi_env & env,napi_value & jsObj,const AudioStandard::InterruptEvent & interruptEvent)84 static void NativeInterruptEventToJsObj(const napi_env& env, napi_value& jsObj,
85     const AudioStandard::InterruptEvent& interruptEvent)
86 {
87     napi_create_object(env, &jsObj);
88     SetValueInt32(env, "eventType", static_cast<int32_t>(interruptEvent.eventType), jsObj);
89     SetValueInt32(env, "forceType", static_cast<int32_t>(interruptEvent.forceType), jsObj);
90     SetValueInt32(env, "hintType", static_cast<int32_t>(interruptEvent.hintType), jsObj);
91 }
92 
OnInterrupt(const AudioStandard::InterruptEvent & interruptEvent)93 void RingtonePlayerCallbackNapi::OnInterrupt(const AudioStandard::InterruptEvent &interruptEvent)
94 {
95     std::lock_guard<std::mutex> lock(mutex_);
96     MEDIA_LOGI("RingtonePlayerCallbackNapi: OnInterrupt is called");
97     MEDIA_LOGI("RingtonePlayerCallbackNapi: hintType: %{public}d", interruptEvent.hintType);
98     CHECK_AND_RETURN_LOG(interruptCallback_ != nullptr, "Cannot find the reference of interrupt callback");
99 
100     std::unique_ptr<RingtonePlayerJsCallback> cb = std::make_unique<RingtonePlayerJsCallback>();
101     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
102     cb->callback = interruptCallback_;
103     cb->callbackName = AUDIO_INTERRUPT_CALLBACK_NAME;
104     cb->interruptEvent = interruptEvent;
105     return OnJsCallbackInterrupt(cb);
106 }
107 
OnJsCallbackInterrupt(std::unique_ptr<RingtonePlayerJsCallback> & jsCb)108 void RingtonePlayerCallbackNapi::OnJsCallbackInterrupt(std::unique_ptr<RingtonePlayerJsCallback> &jsCb)
109 {
110     uv_loop_s *loop = nullptr;
111     napi_get_uv_event_loop(env_, &loop);
112     CHECK_AND_RETURN(loop != nullptr);
113 
114     uv_work_t *work = new(std::nothrow) uv_work_t;
115     CHECK_AND_RETURN_LOG(work != nullptr, "RingtonePlayerCallbackNapi: OnJsCallBackInterrupt: No memory");
116     if (jsCb.get() == nullptr) {
117         MEDIA_LOGE("RingtonePlayerCallbackNapi: OnJsCallBackInterrupt: jsCb.get() is null");
118         delete work;
119         return;
120     }
121     work->data = reinterpret_cast<void *>(jsCb.get());
122 
123     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
124         // Js Thread
125         RingtonePlayerJsCallback *event = reinterpret_cast<RingtonePlayerJsCallback *>(work->data);
126         std::string request = event->callbackName;
127         napi_env env = event->callback->env_;
128         napi_ref callback = event->callback->cb_;
129         napi_handle_scope scope = nullptr;
130         napi_open_handle_scope(env, &scope);
131         MEDIA_LOGI("RingtonePlayerCallbackNapi: JsCallBack %{public}s, uv_queue_work start", request.c_str());
132         do {
133             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s cancelled", request.c_str());
134 
135             napi_value jsCallback = nullptr;
136             napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
137             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
138                 request.c_str());
139 
140             // Call back function
141             napi_value args[1] = { nullptr };
142             NativeInterruptEventToJsObj(env, args[0], event->interruptEvent);
143             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
144                 "%{public}s fail to create Interrupt callback", request.c_str());
145 
146             const size_t argCount = 1;
147             napi_value result = nullptr;
148             nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
149             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call Interrupt callback", request.c_str());
150         } while (0);
151         napi_close_handle_scope(env, scope);
152         delete event;
153         delete work;
154     });
155     if (ret != 0) {
156         MEDIA_LOGE("Failed to execute libuv work queue");
157         delete work;
158     } else {
159         jsCb.release();
160     }
161 }
162 }  // namespace Media
163 }  // namespace OHOS
164