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 #ifndef LOG_TAG
16 #define LOG_TAG "NapiCapturerPositionCallback"
17 #endif
18
19 #include "js_native_api.h"
20 #include "napi_capturer_position_callback.h"
21 #include "napi_audio_capturer_callbacks.h"
22 #include "napi_param_utils.h"
23
24 namespace OHOS {
25 namespace AudioStandard {
NapiCapturerPositionCallback(napi_env env)26 NapiCapturerPositionCallback::NapiCapturerPositionCallback(napi_env env)
27 : env_(env)
28 {
29 AUDIO_DEBUG_LOG("NapiCapturerPositionCallback: instance create");
30 }
31
~NapiCapturerPositionCallback()32 NapiCapturerPositionCallback::~NapiCapturerPositionCallback()
33 {
34 if (regAcPosTsfn_) {
35 napi_release_threadsafe_function(acPosTsfn_, napi_tsfn_abort);
36 }
37 AUDIO_DEBUG_LOG("NapiCapturerPositionCallback: instance destroy");
38 }
39
SaveCallbackReference(const std::string & callbackName,napi_value args)40 void NapiCapturerPositionCallback::SaveCallbackReference(const std::string &callbackName, napi_value args)
41 {
42 std::lock_guard<std::mutex> lock(mutex_);
43 // create function that will operate while save callback reference success.
44 std::function<void(std::shared_ptr<AutoRef> generatedCallback)> successed =
45 [this](std::shared_ptr<AutoRef> generatedCallback) {
46 capturerPositionCallback_ = generatedCallback;
47 };
48 SaveCallbackReferenceInner(callbackName, args, successed);
49 }
50
RemoveCallbackReference(const std::string & callbackName,napi_env env,napi_value callback)51 void NapiCapturerPositionCallback::RemoveCallbackReference(const std::string &callbackName, napi_env env,
52 napi_value callback)
53 {
54 std::lock_guard<std::mutex> lock(mutex_);
55 // create function that will operate while remove callback reference success.
56 std::function<void()> successed =
57 [this]() {
58 capturerPositionCallback_ = nullptr;
59 };
60 RemoveCallbackReferenceInner(callbackName, env, callback, successed);
61 }
62
CreateCapturePositionTsfn(napi_env env)63 void NapiCapturerPositionCallback::CreateCapturePositionTsfn(napi_env env)
64 {
65 regAcPosTsfn_ = true;
66 std::string callbackName = "CapturePosition";
67 napi_value cbName;
68 napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
69 napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0, 1, nullptr,
70 CapturePostionTsfnFinalize, nullptr, SafeJsCallbackCapturerPositionWork, &acPosTsfn_);
71 }
72
GetCapturePositionFlag()73 bool NapiCapturerPositionCallback::GetCapturePositionFlag()
74 {
75 return regAcPosTsfn_;
76 }
77
OnMarkReached(const int64_t & framePosition)78 void NapiCapturerPositionCallback::OnMarkReached(const int64_t &framePosition)
79 {
80 std::lock_guard<std::mutex> lock(mutex_);
81 AUDIO_DEBUG_LOG("NapiCapturerPositionCallback: mark reached");
82 CHECK_AND_RETURN_LOG(capturerPositionCallback_ != nullptr, "Cannot find the reference of position callback");
83
84 std::unique_ptr<CapturerPositionJsCallback> cb = std::make_unique<CapturerPositionJsCallback>();
85 CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
86 cb->callback = capturerPositionCallback_;
87 cb->callbackName = MARK_REACH_CALLBACK_NAME;
88 cb->position = framePosition;
89 return OnJsCapturerPositionCallback(cb);
90 }
91
SafeJsCallbackCapturerPositionWork(napi_env env,napi_value js_cb,void * context,void * data)92 void NapiCapturerPositionCallback::SafeJsCallbackCapturerPositionWork(
93 napi_env env, napi_value js_cb, void *context, void *data)
94 {
95 CapturerPositionJsCallback *event = reinterpret_cast<CapturerPositionJsCallback *>(data);
96 CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr),
97 "OnJsCapturerPositionCallback: no memory");
98 std::shared_ptr<CapturerPositionJsCallback> safeContext(
99 static_cast<CapturerPositionJsCallback*>(data),
100 [](CapturerPositionJsCallback *ptr) {
101 delete ptr;
102 });
103 std::string request = event->callbackName;
104 napi_ref callback = event->callback->cb_;
105 napi_handle_scope scope = nullptr;
106 napi_open_handle_scope(env, &scope);
107 CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
108 AUDIO_INFO_LOG("SafeJsCallbackCapturerPositionWork: safe js callback working.");
109
110 do {
111 napi_value jsCallback = nullptr;
112 napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
113 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
114 request.c_str());
115
116 napi_value args[ARGS_ONE] = { nullptr };
117 napi_create_int64(env, event->position, &args[PARAM0]);
118 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr,
119 "%{public}s fail to create position callback", request.c_str());
120
121 const size_t argCount = ARGS_ONE;
122 napi_value result = nullptr;
123 nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
124 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call position callback", request.c_str());
125 } while (0);
126 napi_close_handle_scope(env, scope);
127 }
128
CapturePostionTsfnFinalize(napi_env env,void * data,void * hint)129 void NapiCapturerPositionCallback::CapturePostionTsfnFinalize(napi_env env, void *data, void *hint)
130 {
131 AUDIO_INFO_LOG("CapturePostionTsfnFinalize: safe thread resource release.");
132 }
133
OnJsCapturerPositionCallback(std::unique_ptr<CapturerPositionJsCallback> & jsCb)134 void NapiCapturerPositionCallback::OnJsCapturerPositionCallback(std::unique_ptr<CapturerPositionJsCallback> &jsCb)
135 {
136 if (jsCb.get() == nullptr) {
137 AUDIO_ERR_LOG("OnJsCapturerPositionCallback: jsCb.get() is null");
138 return;
139 }
140
141 CapturerPositionJsCallback *event = jsCb.release();
142 CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr.");
143
144 napi_acquire_threadsafe_function(acPosTsfn_);
145 napi_call_threadsafe_function(acPosTsfn_, event, napi_tsfn_blocking);
146 }
147
GetEnv()148 napi_env &NapiCapturerPositionCallback::GetEnv()
149 {
150 return env_;
151 }
152
GetCallback(const std::string & callbackName)153 std::shared_ptr<AutoRef> NapiCapturerPositionCallback::GetCallback(const std::string &callbackName)
154 {
155 std::shared_ptr<AutoRef> cb = nullptr;
156 if (callbackName == MARK_REACH_CALLBACK_NAME) {
157 return capturerPositionCallback_;
158 }
159 return cb;
160 }
161
CheckIfTargetCallbackName(const std::string & callbackName)162 bool NapiCapturerPositionCallback::CheckIfTargetCallbackName(const std::string &callbackName)
163 {
164 if (callbackName == MARK_REACH_CALLBACK_NAME) {
165 return true;
166 }
167 return false;
168 }
169 } // namespace AudioStandard
170 } // namespace OHOS