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