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