• 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_player_callback_napi.h"
17 
18 #include <uv.h>
19 
20 #include "media_errors.h"
21 #include "audio_haptic_log.h"
22 #include "audio_haptic_tools.h"
23 
24 namespace {
25 const std::string AUDIO_INTERRUPT_CALLBACK_NAME = "audioInterrupt";
26 const std::string END_OF_STREAM_CALLBACK_NAME = "endOfStream";
27 
28 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticPlayerCallbackNapi"};
29 }
30 
31 namespace OHOS {
32 namespace Media {
AudioHapticPlayerCallbackNapi(napi_env env)33 AudioHapticPlayerCallbackNapi::AudioHapticPlayerCallbackNapi(napi_env env)
34     : env_(env)
35 {
36     MEDIA_LOGI("AudioHapticPlayerCallbackNapi: instance create");
37 }
38 
~AudioHapticPlayerCallbackNapi()39 AudioHapticPlayerCallbackNapi::~AudioHapticPlayerCallbackNapi()
40 {
41     MEDIA_LOGI("~AudioHapticPlayerCallbackNapi: instance destroy");
42 }
43 
SaveCallbackReference(const std::string & callbackName,napi_value args)44 void AudioHapticPlayerCallbackNapi::SaveCallbackReference(const std::string &callbackName, napi_value args)
45 {
46     std::lock_guard<std::mutex> lock(cbMutex_);
47 
48     napi_ref callback = nullptr;
49     const int32_t refCount = 1;
50     napi_status status = napi_create_reference(env_, args, refCount, &callback);
51     CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
52         "SaveCallbackReference: creating reference for callback fail");
53 
54     std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
55     if (callbackName == AUDIO_INTERRUPT_CALLBACK_NAME) {
56         audioInterruptCb_ = cb;
57     } else if (callbackName == END_OF_STREAM_CALLBACK_NAME) {
58         endOfStreamCb_ = cb;
59     } else {
60         MEDIA_LOGE("SaveCallbackReference: Unknown callback type: %{public}s", callbackName.c_str());
61     }
62 }
63 
RemoveCallbackReference(const std::string & callbackName)64 void AudioHapticPlayerCallbackNapi::RemoveCallbackReference(const std::string &callbackName)
65 {
66     std::lock_guard<std::mutex> lock(cbMutex_);
67 
68     if (callbackName == AUDIO_INTERRUPT_CALLBACK_NAME) {
69         audioInterruptCb_ = nullptr;
70     } else if (callbackName == END_OF_STREAM_CALLBACK_NAME) {
71         endOfStreamCb_ = nullptr;
72     } else {
73         MEDIA_LOGE("RemoveCallbackReference: Unknown callback type: %{public}s", callbackName.c_str());
74     }
75 }
76 
SetValueInt32(const napi_env & env,const std::string & fieldStr,const int intValue,napi_value & result)77 static void SetValueInt32(const napi_env& env, const std::string& fieldStr, const int intValue, napi_value& result)
78 {
79     napi_handle_scope scope = nullptr;
80     napi_open_handle_scope(env, &scope);
81 
82     napi_value value = nullptr;
83     napi_create_int32(env, intValue, &value);
84     napi_set_named_property(env, result, fieldStr.c_str(), value);
85 
86     napi_close_handle_scope(env, scope);
87 }
88 
NativeInterruptEventToJsObj(const napi_env & env,napi_value & jsObj,const AudioStandard::InterruptEvent & interruptEvent)89 static void NativeInterruptEventToJsObj(const napi_env& env, napi_value& jsObj,
90     const AudioStandard::InterruptEvent& interruptEvent)
91 {
92     napi_create_object(env, &jsObj);
93     SetValueInt32(env, "eventType", static_cast<int32_t>(interruptEvent.eventType), jsObj);
94     SetValueInt32(env, "forceType", static_cast<int32_t>(interruptEvent.forceType), jsObj);
95     SetValueInt32(env, "hintType", static_cast<int32_t>(interruptEvent.hintType), jsObj);
96 }
97 
OnInterrupt(const AudioStandard::InterruptEvent & interruptEvent)98 void AudioHapticPlayerCallbackNapi::OnInterrupt(const AudioStandard::InterruptEvent &interruptEvent)
99 {
100     std::lock_guard<std::mutex> lock(cbMutex_);
101     MEDIA_LOGI("OnInterrupt: hintType: %{public}d for js", interruptEvent.hintType);
102     CHECK_AND_RETURN_LOG(audioInterruptCb_ != nullptr, "Cannot find the reference of interrupt callback");
103 
104     std::unique_ptr<AudioHapticPlayerJsCallback> cb = std::make_unique<AudioHapticPlayerJsCallback>();
105     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
106     cb->callback = audioInterruptCb_;
107     cb->callbackName = AUDIO_INTERRUPT_CALLBACK_NAME;
108     cb->interruptEvent = interruptEvent;
109     return OnInterruptJsCallback(cb);
110 }
111 
OnInterruptJsCallback(std::unique_ptr<AudioHapticPlayerJsCallback> & jsCb)112 void AudioHapticPlayerCallbackNapi::OnInterruptJsCallback(std::unique_ptr<AudioHapticPlayerJsCallback> &jsCb)
113 {
114     if (jsCb.get() == nullptr) {
115         MEDIA_LOGE("AudioHapticPlayerJsCallback: jsCb.get() is null");
116         return;
117     }
118     ObjectRefMap objectGuard(jsCb.get());
119     AudioHapticPlayerJsCallback *object = objectGuard.GetPtr();
120     auto task = [object]() {
121         std::shared_ptr<AudioHapticPlayerJsCallback> context(
122             static_cast<AudioHapticPlayerJsCallback*>(object),
123             [](AudioHapticPlayerJsCallback* ptr) {
124                 delete ptr;
125         });
126         CHECK_AND_RETURN_LOG(object != nullptr, "event is nullptr");
127         std::string request = object->callbackName;
128         napi_env env = object->callback->env_;
129         napi_ref callback = object->callback->cb_;
130         napi_handle_scope scope = nullptr;
131         napi_open_handle_scope(env, &scope);
132         MEDIA_LOGI("AudioHapticPlayerJsCallback: %{public}s JsCallBack, uv_queue_work start", request.c_str());
133         do {
134             CHECK_AND_BREAK_LOG(object != nullptr, "object is nullptr");
135 
136             napi_value jsCallback = nullptr;
137             napi_status napiStatus = napi_get_reference_value(env, callback, &jsCallback);
138             CHECK_AND_BREAK_LOG(napiStatus == napi_ok && jsCallback != nullptr,
139                 "%{public}s get reference value fail", request.c_str());
140 
141             // Call back function
142             napi_value args[1] = { nullptr };
143             NativeInterruptEventToJsObj(env, args[0], object->interruptEvent);
144             CHECK_AND_BREAK_LOG(napiStatus == napi_ok && args[0] != nullptr,
145                 "%{public}s fail to create Interrupt callback", request.c_str());
146 
147             const size_t argCount = 1;
148             napi_value result = nullptr;
149             napiStatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
150             CHECK_AND_BREAK_LOG(napiStatus == napi_ok, "%{public}s fail to send interrupt callback", request.c_str());
151         } while (0);
152         napi_close_handle_scope(env, scope);
153         delete object;
154     };
155     auto ret = napi_send_event(env_, task, napi_eprio_high);
156     if (ret != napi_status::napi_ok) {
157         MEDIA_LOGE("Failed to SendEvent, ret = %{public}d", ret);
158         jsCb.release();
159     }
160 }
161 
OnEndOfStream(void)162 void AudioHapticPlayerCallbackNapi::OnEndOfStream(void)
163 {
164     std::lock_guard<std::mutex> lock(cbMutex_);
165     MEDIA_LOGI("OnEndOfStream in succeed");
166     CHECK_AND_RETURN_LOG(endOfStreamCb_ != nullptr, "Cannot find the reference of endOfStream callback");
167 
168     std::unique_ptr<AudioHapticPlayerJsCallback> cb = std::make_unique<AudioHapticPlayerJsCallback>();
169     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
170     cb->callback = endOfStreamCb_;
171     cb->callbackName = END_OF_STREAM_CALLBACK_NAME;
172     return OnEndOfStreamJsCallback(cb);
173 }
174 
OnError(int32_t errorCode)175 void AudioHapticPlayerCallbackNapi::OnError(int32_t errorCode)
176 {
177     MEDIA_LOGI("OnError from audio haptic player. errorCode %{public}d", errorCode);
178 }
179 
OnEndOfStreamJsCallback(std::unique_ptr<AudioHapticPlayerJsCallback> & jsCb)180 void AudioHapticPlayerCallbackNapi::OnEndOfStreamJsCallback(std::unique_ptr<AudioHapticPlayerJsCallback> &jsCb)
181 {
182     if (jsCb.get() == nullptr) {
183         MEDIA_LOGE("AudioHapticPlayerJsCallback: jsCb.get() is null");
184         return;
185     }
186     ObjectRefMap objectGuard(jsCb.get());
187     AudioHapticPlayerJsCallback *object = objectGuard.GetPtr();
188     auto task = [object]() {
189         std::shared_ptr<AudioHapticPlayerJsCallback> context(
190             static_cast<AudioHapticPlayerJsCallback*>(object),
191             [](AudioHapticPlayerJsCallback* ptr) {
192                 delete ptr;
193         });
194         CHECK_AND_RETURN_LOG(object != nullptr, "object is nullptr");
195         std::string request = object->callbackName;
196         napi_env env = object->callback->env_;
197         napi_ref callback = object->callback->cb_;
198         napi_handle_scope scope = nullptr;
199         napi_open_handle_scope(env, &scope);
200         MEDIA_LOGI("OnEndOfStreamJsCallback: %{public}s JsCallBack, uv_queue_work start", request.c_str());
201         do {
202             CHECK_AND_BREAK_LOG(object != nullptr, "object is nullptr");
203 
204             napi_value jsCallback = nullptr;
205             napi_status napiStatus = napi_get_reference_value(env, callback, &jsCallback);
206             CHECK_AND_BREAK_LOG(napiStatus == napi_ok && jsCallback != nullptr,
207                 "%{public}s get reference value fail", request.c_str());
208 
209             // Call back function
210             napi_value result = nullptr;
211             napiStatus = napi_call_function(env, nullptr, jsCallback, 0, nullptr, &result);
212             CHECK_AND_BREAK_LOG(napiStatus == napi_ok, "%{public}s fail to send interrupt callback", request.c_str());
213         } while (0);
214         napi_close_handle_scope(env, scope);
215         delete object;
216     };
217     auto ret = napi_send_event(env_, task, napi_eprio_high);
218     if (ret != napi_status::napi_ok) {
219         MEDIA_LOGE("Failed to SendEvent, ret = %{public}d", ret);
220         jsCb.release();
221     }
222 }
223 }  // namespace Media
224 }  // namespace OHOS
225