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 "napi_renderer_period_position_callback.h"
20 #include "audio_errors.h"
21 #include "audio_renderer_log.h"
22 #include "napi_audio_renderer_callback.h"
23
24 namespace OHOS {
25 namespace AudioStandard {
NapiRendererPeriodPositionCallback(napi_env env)26 NapiRendererPeriodPositionCallback::NapiRendererPeriodPositionCallback(napi_env env)
27 : env_(env)
28 {
29 AUDIO_DEBUG_LOG("instance create");
30 }
31
~NapiRendererPeriodPositionCallback()32 NapiRendererPeriodPositionCallback::~NapiRendererPeriodPositionCallback()
33 {
34 AUDIO_DEBUG_LOG("instance destroy");
35 }
36
SaveCallbackReference(const std::string & callbackName,napi_value args)37 void NapiRendererPeriodPositionCallback::SaveCallbackReference(const std::string &callbackName, napi_value args)
38 {
39 std::lock_guard<std::mutex> lock(mutex_);
40 napi_ref callback = nullptr;
41 const int32_t refCount = 1;
42 napi_status status = napi_create_reference(env_, args, refCount, &callback);
43 CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
44 "creating reference for callback fail");
45
46 std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
47 if (callbackName == PERIOD_REACH_CALLBACK_NAME) {
48 renderPeriodPositionCallback_ = cb;
49 } else {
50 AUDIO_ERR_LOG("Unknown callback type: %{public}s", callbackName.c_str());
51 }
52 }
53
OnPeriodReached(const int64_t & frameNumber)54 void NapiRendererPeriodPositionCallback::OnPeriodReached(const int64_t &frameNumber)
55 {
56 std::lock_guard<std::mutex> lock(mutex_);
57 AUDIO_DEBUG_LOG("period reached");
58 CHECK_AND_RETURN_LOG(renderPeriodPositionCallback_ != nullptr, "Cannot find the reference of position callback");
59
60 std::unique_ptr<RendererPeriodPositionJsCallback> cb = std::make_unique<RendererPeriodPositionJsCallback>();
61 CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
62 cb->callback = renderPeriodPositionCallback_;
63 cb->callbackName = PERIOD_REACH_CALLBACK_NAME;
64 cb->position = frameNumber;
65 return OnJsRendererPeriodPositionCallback(cb);
66 }
67
WorkCallbackRendererPeriodPosition(uv_work_t * work,int status)68 void NapiRendererPeriodPositionCallback::WorkCallbackRendererPeriodPosition(uv_work_t *work, int status)
69 {
70 // Js Thread
71 std::shared_ptr<RendererPeriodPositionJsCallback> context(
72 static_cast<RendererPeriodPositionJsCallback*>(work->data),
73 [work](RendererPeriodPositionJsCallback* ptr) {
74 delete ptr;
75 delete work;
76 });
77 CHECK_AND_RETURN_LOG(work != nullptr, "WorkCallbackRendererPeriodPosition work is nullptr");
78 RendererPeriodPositionJsCallback *event = reinterpret_cast<RendererPeriodPositionJsCallback *>(work->data);
79 CHECK_AND_RETURN_LOG(event != nullptr, "WorkCallbackRendererPeriodPosition event is nullptr");
80 std::string request = event->callbackName;
81
82 CHECK_AND_RETURN_LOG(event->callback != nullptr, "event->callback is nullptr");
83 napi_env env = event->callback->env_;
84 napi_ref callback = event->callback->cb_;
85
86 napi_handle_scope scope = nullptr;
87 napi_open_handle_scope(env, &scope);
88 CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
89 do {
90 CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
91 napi_value jsCallback = nullptr;
92 napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
93 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
94 request.c_str());
95
96 // Call back function
97 napi_value args[ARGS_ONE] = { nullptr };
98 nstatus = NapiParamUtils::SetValueInt64(env, event->position, args[0]);
99 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr,
100 "%{public}s fail to create position callback", request.c_str());
101
102 const size_t argCount = 1;
103 napi_value result = nullptr;
104 nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
105 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call position callback", request.c_str());
106 } while (0);
107 napi_close_handle_scope(env, scope);
108 }
109
OnJsRendererPeriodPositionCallback(std::unique_ptr<RendererPeriodPositionJsCallback> & jsCb)110 void NapiRendererPeriodPositionCallback::OnJsRendererPeriodPositionCallback(
111 std::unique_ptr<RendererPeriodPositionJsCallback> &jsCb)
112 {
113 uv_loop_s *loop = nullptr;
114 CHECK_AND_RETURN_LOG(env_ != nullptr, "OnJsRendererPeriodPositionCallback: env_ is null");
115 napi_get_uv_event_loop(env_, &loop);
116 CHECK_AND_RETURN_LOG(loop != nullptr, "loop is null: No memory");
117
118 uv_work_t *work = new(std::nothrow) uv_work_t;
119 CHECK_AND_RETURN_LOG(work != nullptr, "OnJsRendererPeriodPositionCallback: No memory");
120
121 if (jsCb.get() == nullptr) {
122 AUDIO_ERR_LOG("OnJsRendererPeriodPositionCallback: jsCb.get() is null");
123 delete work;
124 return;
125 }
126 work->data = reinterpret_cast<void *>(jsCb.get());
127 int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {},
128 WorkCallbackRendererPeriodPosition, uv_qos_default);
129 if (ret != 0) {
130 AUDIO_ERR_LOG("Failed to execute libuv work queue");
131 delete work;
132 } else {
133 jsCb.release();
134 }
135 }
136 } // namespace AudioStandard
137 } // namespace OHOS
138