• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "NapiAudioSessionStateCallback"
17 #endif
18 #include <thread>
19 #include "js_native_api.h"
20 #include "napi_audio_session_state_callback.h"
21 #include "napi_param_utils.h"
22 #include "napi/native_api.h"
23 
24 namespace OHOS {
25 namespace AudioStandard {
NapiAudioSessionStateCallback(napi_env env)26 NapiAudioSessionStateCallback::NapiAudioSessionStateCallback(napi_env env)
27     :env_(env)
28 {
29     AUDIO_DEBUG_LOG("NapiAudioSessionStateCallback::Constructor");
30 }
31 
~NapiAudioSessionStateCallback()32 NapiAudioSessionStateCallback::~NapiAudioSessionStateCallback()
33 {
34     if (regAmSessionStateChgTsfn_) {
35         napi_release_threadsafe_function(amSessionStateChgTsfn_, napi_tsfn_abort);
36     }
37     AUDIO_DEBUG_LOG("NapiAudioSessionStateCallback::Destructor");
38 }
39 
OnAudioSessionStateChanged(const AudioSessionStateChangedEvent & stateEvent)40 void NapiAudioSessionStateCallback::OnAudioSessionStateChanged(const AudioSessionStateChangedEvent &stateEvent)
41 {
42     AUDIO_INFO_LOG("OnAudioSessionStateChanged is called AudioSessionStateChangedEvent=%{public}d",
43         stateEvent.stateChangeHint);
44     CHECK_AND_RETURN_LOG(audioSessionStateJsCallback_ != nullptr,
45         "OnAudioSessionStateChanged:No JS callback registered return");
46     std::unique_ptr<AudioSessionStateJsCallback> cb = std::make_unique<AudioSessionStateJsCallback>();
47     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
48     cb->callback = audioSessionStateJsCallback_;
49     cb->callbackName = AUDIO_SESSION_STATE_CALLBACK_NAME;
50     cb->audioSessionStateEvent.stateChangeHint = stateEvent.stateChangeHint;
51 
52     return OnJsCallbackAudioSessionState(cb);
53 }
54 
SaveCallbackReference(napi_value args)55 void NapiAudioSessionStateCallback::SaveCallbackReference(napi_value args)
56 {
57     std::lock_guard<std::mutex> lock(mutex_);
58     napi_ref callback = nullptr;
59     const int32_t refCount = 1;
60     napi_status status = napi_create_reference(env_, args, refCount, &callback);
61     CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
62         "NapiAudioSessionStateCallback: creating reference for callback fail");
63     callback_ = callback;
64     std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
65     audioSessionStateJsCallback_ = cb;
66 }
67 
CreateAudioSessionStateTsfn(napi_env env)68 void NapiAudioSessionStateCallback::CreateAudioSessionStateTsfn(napi_env env)
69 {
70     regAmSessionStateChgTsfn_ = true;
71     std::string callbackName = "audioSessionStateChanged";
72     napi_value cbName;
73     napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
74     napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0, 1, nullptr, AudioSessionStateTsfnFinalize,
75         nullptr, SafeJsCallbackAudioSessionStateWork, &amSessionStateChgTsfn_);
76 }
77 
GetAudioSessionStateTsfnFlag() const78 bool NapiAudioSessionStateCallback::GetAudioSessionStateTsfnFlag() const
79 {
80     return regAmSessionStateChgTsfn_;
81 }
82 
SafeJsCallbackAudioSessionStateWork(napi_env env,napi_value js_cb,void * context,void * data)83 void NapiAudioSessionStateCallback::SafeJsCallbackAudioSessionStateWork(
84     napi_env env, napi_value js_cb, void *context, void *data)
85 {
86     AudioSessionStateJsCallback *event = reinterpret_cast<AudioSessionStateJsCallback *>(data);
87     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr),
88         "OnJsCallbackAudioSessionState: no memory");
89 
90     std::string request = event->callbackName;
91     napi_ref callback = event->callback->cb_;
92     napi_handle_scope scope = nullptr;
93     napi_open_handle_scope(env, &scope);
94     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
95     AUDIO_INFO_LOG("SafeJsCallbackAudioSessionStateWork: safe js callback working.");
96     do {
97         napi_value jsCallback = nullptr;
98         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
99         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
100             request.c_str());
101 
102         napi_value args[ARGS_ONE] = { nullptr };
103         napi_create_object(env, &args[PARAM0]);
104         NapiParamUtils::SetValueInt32(env, "stateChangeHint",
105             static_cast<int32_t>(event->audioSessionStateEvent.stateChangeHint), args[PARAM0]);
106         CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr,
107             "%{public}s fail to stateChangeHint callback", request.c_str());
108 
109         const size_t argCount = ARGS_ONE;
110         napi_value result = nullptr;
111         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
112         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call SetaudioSessionState callback",
113             request.c_str());
114     } while (0);
115     napi_close_handle_scope(env, scope);
116 }
117 
AudioSessionStateTsfnFinalize(napi_env env,void * data,void * hint)118 void NapiAudioSessionStateCallback::AudioSessionStateTsfnFinalize(napi_env env, void *data, void *hint)
119 {
120     AUDIO_INFO_LOG("AudioSessionStateTsfnFinalize: safe thread resource release.");
121 }
122 
OnJsCallbackAudioSessionState(std::unique_ptr<AudioSessionStateJsCallback> & jsCb)123 void NapiAudioSessionStateCallback::OnJsCallbackAudioSessionState(std::unique_ptr<AudioSessionStateJsCallback> &jsCb)
124 {
125     if (jsCb.get() == nullptr) {
126         AUDIO_ERR_LOG("NapiAudioSessionStateCallback: OnJsCallbackAudioSessionState: jsCb.get() is null");
127         return;
128     }
129 
130     AudioSessionStateJsCallback *event = jsCb.release();
131     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr.");
132 
133     napi_acquire_threadsafe_function(amSessionStateChgTsfn_);
134     napi_call_threadsafe_function(amSessionStateChgTsfn_, event, napi_tsfn_blocking);
135 }
136 
ContainSameJsCallback(napi_value args)137 bool NapiAudioSessionStateCallback::ContainSameJsCallback(napi_value args)
138 {
139     bool isEquals = false;
140     napi_value copyValue = nullptr;
141 
142     napi_get_reference_value(env_, callback_, &copyValue);
143     CHECK_AND_RETURN_RET_LOG(args != nullptr, false, "args is nullptr");
144     CHECK_AND_RETURN_RET_LOG(napi_strict_equals(env_, copyValue, args, &isEquals) == napi_ok, false,
145         "Get napi_strict_equals failed");
146 
147     return isEquals;
148 }
149 } // namespace AudioStandard
150 } // namespace OHOS