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 "NapiAudioCapturerDeviceChangeCallback"
17 #endif
18
19 #include "js_native_api.h"
20 #include "napi_audio_capturer_device_change_callback.h"
21 #include "audio_errors.h"
22 #include "audio_capturer_log.h"
23 #include "napi_param_utils.h"
24
25 using namespace std;
26
27 namespace OHOS {
28 namespace AudioStandard {
NapiAudioCapturerDeviceChangeCallback(napi_env env)29 NapiAudioCapturerDeviceChangeCallback::NapiAudioCapturerDeviceChangeCallback(napi_env env)
30 : env_(env)
31 {
32 AUDIO_DEBUG_LOG("Instance create");
33 }
34
~NapiAudioCapturerDeviceChangeCallback()35 NapiAudioCapturerDeviceChangeCallback::~NapiAudioCapturerDeviceChangeCallback()
36 {
37 if (regAcDevChgTsfn_) {
38 napi_release_threadsafe_function(acDevChgTsfn_, napi_tsfn_abort);
39 }
40 AUDIO_DEBUG_LOG("Instance destroy");
41 }
42
SaveCallbackReference(const std::string & callbackName,napi_value args)43 void NapiAudioCapturerDeviceChangeCallback::SaveCallbackReference(const std::string &callbackName, napi_value args)
44 {
45 std::lock_guard<std::mutex> lock(mutex_);
46 // create function that will operate while save callback reference success.
47 std::function<void(std::shared_ptr<AutoRef> generatedCallback)> successed =
48 [this](std::shared_ptr<AutoRef> generatedCallback) {
49 callbackPtr_ = generatedCallback;
50 callback_ = callbackPtr_->cb_;
51 };
52 NapiAudioCapturerCallbackInner::SaveCallbackReferenceInner(callbackName, args, successed);
53 }
54
RemoveCallbackReference(const std::string & callbackName,napi_env env,napi_value callback)55 void NapiAudioCapturerDeviceChangeCallback::RemoveCallbackReference(
56 const std::string &callbackName, napi_env env, napi_value callback)
57 {
58 std::lock_guard<std::mutex> lock(mutex_);
59 std::function<void()> successed = [this]() {
60 callbackPtr_ = nullptr;
61 callback_ = nullptr;
62 };
63 NapiAudioCapturerCallbackInner::RemoveCallbackReferenceInner(callbackName, env, callback, successed);
64 }
65
CreateCaptureDeviceChangeTsfn(napi_env env)66 void NapiAudioCapturerDeviceChangeCallback::CreateCaptureDeviceChangeTsfn(napi_env env)
67 {
68 regAcDevChgTsfn_ = true;
69 napi_value cbName;
70 std::string callbackName = "AudioCapturerDeviceChange";
71 napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
72 napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0, 1, nullptr, CaptureDeviceInfoTsfnFinalize,
73 nullptr, SafeJsCallbackCapturerDeviceInfoWork, &acDevChgTsfn_);
74 }
75
ContainSameJsCallback(napi_value args)76 bool NapiAudioCapturerDeviceChangeCallback::ContainSameJsCallback(napi_value args)
77 {
78 bool isEquals = false;
79 napi_value copyValue = nullptr;
80
81 napi_get_reference_value(env_, callback_, ©Value);
82 CHECK_AND_RETURN_RET_LOG(args != nullptr, false, "args is nullptr");
83
84 CHECK_AND_RETURN_RET_LOG(napi_strict_equals(env_, copyValue, args, &isEquals) == napi_ok, false,
85 "Get napi_strict_equals failed");
86
87 return isEquals;
88 }
89
OnStateChange(const AudioDeviceDescriptor & deviceInfo)90 void NapiAudioCapturerDeviceChangeCallback::OnStateChange(const AudioDeviceDescriptor &deviceInfo)
91 {
92 OnJsCallbackCapturerDeviceInfo(callback_, deviceInfo);
93 }
94
SafeJsCallbackCapturerDeviceInfoWork(napi_env env,napi_value js_cb,void * context,void * data)95 void NapiAudioCapturerDeviceChangeCallback::SafeJsCallbackCapturerDeviceInfoWork(
96 napi_env env, napi_value js_cb, void *context, void *data)
97 {
98 AudioCapturerDeviceChangeJsCallback *event = reinterpret_cast<AudioCapturerDeviceChangeJsCallback *>(data);
99 CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback_) != nullptr,
100 "OnJsCallbackCapturerDeviceInfo: no memory");
101 std::shared_ptr<AudioCapturerDeviceChangeJsCallback> safeContext(
102 static_cast<AudioCapturerDeviceChangeJsCallback*>(data),
103 [](AudioCapturerDeviceChangeJsCallback *ptr) {
104 delete ptr;
105 });
106 napi_ref callback = event->callback_;
107 napi_handle_scope scope = nullptr;
108 napi_open_handle_scope(env, &scope);
109 CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
110 AUDIO_INFO_LOG("SafeJsCallbackCapturerDeviceInfoWork: safe js callback working.");
111 do {
112 napi_value jsCallback = nullptr;
113 napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
114 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "Callback get reference value fail");
115 // Call back function
116 napi_value args[ARGS_ONE] = { nullptr };
117 NapiParamUtils::SetValueDeviceInfo(env, event->deviceInfo_, args[0]);
118 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr,
119 " Fail to convert to jsobj");
120 const size_t argCount = ARGS_ONE;
121 napi_value result = nullptr;
122 nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
123 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call devicechange callback");
124 } while (0);
125 napi_close_handle_scope(env, scope);
126 }
127
CaptureDeviceInfoTsfnFinalize(napi_env env,void * data,void * hint)128 void NapiAudioCapturerDeviceChangeCallback::CaptureDeviceInfoTsfnFinalize(napi_env env, void *data, void *hint)
129 {
130 AUDIO_INFO_LOG("RingModeTsfnFinalize: safe thread resource release.");
131 }
132
OnJsCallbackCapturerDeviceInfo(napi_ref method,const AudioDeviceDescriptor & deviceInfo)133 void NapiAudioCapturerDeviceChangeCallback::OnJsCallbackCapturerDeviceInfo(napi_ref method,
134 const AudioDeviceDescriptor &deviceInfo)
135 {
136 CHECK_AND_RETURN_LOG(method != nullptr, "method is nullptr");
137 AudioCapturerDeviceChangeJsCallback *event = new AudioCapturerDeviceChangeJsCallback {method, env_, deviceInfo};
138
139 if (event == nullptr) {
140 AUDIO_ERR_LOG("event data malloc failed: No memory");
141 return;
142 }
143
144 napi_acquire_threadsafe_function(acDevChgTsfn_);
145 napi_call_threadsafe_function(acDevChgTsfn_, event, napi_tsfn_blocking);
146 }
147
GetEnv()148 napi_env &NapiAudioCapturerDeviceChangeCallback::GetEnv()
149 {
150 return env_;
151 }
152
GetCallback(const std::string & callbackName)153 std::shared_ptr<AutoRef> NapiAudioCapturerDeviceChangeCallback::GetCallback(const std::string &callbackName)
154 {
155 return callbackPtr_;
156 }
157
CheckIfTargetCallbackName(const std::string & callbackName)158 bool NapiAudioCapturerDeviceChangeCallback::CheckIfTargetCallbackName(const std::string &callbackName)
159 {
160 return (callbackName == INPUTDEVICE_CHANGE_CALLBACK_NAME);
161 }
162 } // namespace AudioStandard
163 } // namespace OHOS
164