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