1 /*
2 * Copyright (c) 2022-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
16 #include <memory>
17
18 #include "avsession_log.h"
19 #include "avsession_info.h"
20 #include "avsession_trace.h"
21 #include "napi_session_listener.h"
22 #include "avsession_controller.h"
23 #include "avsession_controller_proxy.h"
24
25 namespace OHOS::AVSession {
NapiSessionListener()26 NapiSessionListener::NapiSessionListener()
27 {
28 SLOGI("construct");
29 isValid_ = std::make_shared<bool>(true);
30 }
31
~NapiSessionListener()32 NapiSessionListener::~NapiSessionListener()
33 {
34 SLOGI("destroy.");
35 std::lock_guard<std::mutex> lockGuard(lock_);
36 *isValid_ = false;
37 }
38
39 template<typename T>
HandleEvent(int32_t event,const T & param)40 void NapiSessionListener::HandleEvent(int32_t event, const T& param)
41 {
42 std::lock_guard<std::mutex> lockGuard(lock_);
43 if (callbacks_[event].empty()) {
44 SLOGE("not register callback event=%{public}d", event);
45 return;
46 }
47
48 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
49 SLOGI("call with flag for event %{public}d", event);
50 asyncCallback_->CallWithFunc(*ref, isValid_,
51 [this, ref, event]() {
52 std::lock_guard<std::mutex> lockGuard(lock_);
53 if (callbacks_[event].empty()) {
54 SLOGE("checkCallbackValid with empty list for event %{public}d", event);
55 return false;
56 }
57 bool hasFunc = false;
58 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
59 hasFunc = (ref == it ? true : hasFunc);
60 }
61 SLOGD("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
62 return hasFunc;
63 },
64 [param](napi_env env, int& argc, napi_value* argv) {
65 argc = 1;
66 NapiUtils::SetValue(env, param, *argv);
67 });
68 }
69 }
70
71 template<typename T>
HandleEvent(int32_t event,const T & param,bool checkValid)72 void NapiSessionListener::HandleEvent(int32_t event, const T& param, bool checkValid)
73 {
74 std::lock_guard<std::mutex> lockGuard(lock_);
75 if (callbacks_[event].empty()) {
76 SLOGE("not register callback event=%{public}d", event);
77 return;
78 }
79 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
80 SLOGI("call with flag for event %{public}d", event);
81 asyncCallback_->CallWithFunc(*ref, isValid_,
82 [this, ref, event]() {
83 std::lock_guard<std::mutex> lockGuard(lock_);
84 if (callbacks_[event].empty()) {
85 SLOGE("checkCallbackValid with empty list for event %{public}d", event);
86 return false;
87 }
88 bool hasFunc = false;
89 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
90 hasFunc = (ref == it ? true : hasFunc);
91 }
92 SLOGD("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
93 return hasFunc;
94 },
95 [param](napi_env env, int& argc, napi_value* argv) {
96 argc = 1;
97 NapiUtils::SetValue(env, param, *argv);
98 });
99 }
100 SLOGI("handle event %{public}d", static_cast<int32_t>(event));
101 }
102
103 template<typename T, typename N>
HandleEvent(int32_t event,const T & firstParam,const N & secondParam)104 void NapiSessionListener::HandleEvent(int32_t event, const T& firstParam, const N& secondParam)
105 {
106 std::lock_guard<std::mutex> lockGuard(lock_);
107 if (callbacks_[event].empty()) {
108 SLOGE("not register callback event=%{public}d", event);
109 return;
110 }
111
112 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
113 SLOGI("call with flag for event %{public}d", event);
114 asyncCallback_->CallWithFunc(*ref, isValid_,
115 [this, ref, event]() {
116 std::lock_guard<std::mutex> lockGuard(lock_);
117 if (callbacks_[event].empty()) {
118 SLOGE("checkCallbackValid with empty list for event %{public}d", event);
119 return false;
120 }
121 bool hasFunc = false;
122 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
123 hasFunc = (ref == it ? true : hasFunc);
124 }
125 SLOGD("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
126 return hasFunc;
127 },
128 [firstParam, secondParam](napi_env env, int& argc, napi_value* argv) {
129 argc = NapiUtils::ARGC_TWO;
130 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
131 CHECK_RETURN_VOID(status == napi_ok, "set firstParam invalid");
132 status = NapiUtils::SetValue(env, secondParam, argv[1]);
133 CHECK_RETURN_VOID(status == napi_ok, "set secondParam invalid");
134 });
135 }
136 SLOGI("handle event %{public}d", static_cast<int32_t>(event));
137 }
138
OnSessionCreate(const AVSessionDescriptor & descriptor)139 void NapiSessionListener::OnSessionCreate(const AVSessionDescriptor& descriptor)
140 {
141 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnSessionCreate");
142 SLOGI("sessionId=%{public}s***", descriptor.sessionId_.substr(0, UNMASK_CHAR_NUM).c_str());
143 HandleEvent(EVENT_SESSION_CREATED, descriptor);
144 }
145
OnSessionRelease(const AVSessionDescriptor & descriptor)146 void NapiSessionListener::OnSessionRelease(const AVSessionDescriptor& descriptor)
147 {
148 SLOGI("sessionId=%{public}s***", descriptor.sessionId_.substr(0, UNMASK_CHAR_NUM).c_str());
149 HandleEvent(EVENT_SESSION_DESTROYED, descriptor);
150 }
151
OnTopSessionChange(const AVSessionDescriptor & descriptor)152 void NapiSessionListener::OnTopSessionChange(const AVSessionDescriptor& descriptor)
153 {
154 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnTopSessionChange");
155 SLOGI("sessionId=%{public}s***", descriptor.sessionId_.substr(0, UNMASK_CHAR_NUM).c_str());
156 HandleEvent(EVENT_TOP_SESSION_CHANGED, descriptor);
157 }
158
OnAudioSessionChecked(const int32_t uid)159 void NapiSessionListener::OnAudioSessionChecked(const int32_t uid)
160 {
161 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnAudioSessionCheck");
162 SLOGI("uid=%{public}d checked", uid);
163 HandleEvent(EVENT_AUDIO_SESSION_CHECKED, uid);
164 }
165
OnDeviceAvailable(const OutputDeviceInfo & castOutputDeviceInfo)166 void NapiSessionListener::OnDeviceAvailable(const OutputDeviceInfo& castOutputDeviceInfo)
167 {
168 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnDeviceAvailable");
169 SLOGI("Start handle device found event");
170 HandleEvent(EVENT_DEVICE_AVAILABLE, castOutputDeviceInfo, true);
171 }
172
OnDeviceLogEvent(const DeviceLogEventCode eventId,const int64_t param)173 void NapiSessionListener::OnDeviceLogEvent(const DeviceLogEventCode eventId, const int64_t param)
174 {
175 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnDeviceLogEvent");
176 SLOGI("Start device log event");
177 HandleEvent(EVENT_DEVICE_LOG_EVENT, eventId, param);
178 }
179
OnDeviceOffline(const std::string & deviceId)180 void NapiSessionListener::OnDeviceOffline(const std::string& deviceId)
181 {
182 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnDeviceOffline");
183 SLOGI("Start handle device offline event");
184 HandleEvent(EVENT_DEVICE_OFFLINE, deviceId);
185 }
186
OnRemoteDistributedSessionChange(const std::vector<sptr<IRemoteObject>> & sessionControllers)187 void NapiSessionListener::OnRemoteDistributedSessionChange(
188 const std::vector<sptr<IRemoteObject>>& sessionControllers)
189 {
190 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnRemoteDistributedSessionChange");
191 SLOGI("Start handle remote distributed session changed event");
192 std::vector<std::shared_ptr<AVSessionController>> sessionControllersRef;
193 for (auto& object: sessionControllers) {
194 auto controllerObject = iface_cast<AVSessionControllerProxy>(object);
195 sessionControllersRef.push_back(std::shared_ptr<AVSessionController>(controllerObject.GetRefPtr(),
196 [holder = controllerObject](const auto*) {}));
197 }
198 SLOGI("handle remote distributed session changed end size=%{public}d", (int) sessionControllersRef.size());
199 HandleEvent(EVENT_REMOTE_DISTRIBUTED_SESSION_CHANGED, sessionControllersRef);
200 }
201
OnDeviceStateChange(const DeviceState & deviceState)202 void NapiSessionListener::OnDeviceStateChange(const DeviceState& deviceState)
203 {
204 AVSESSION_TRACE_SYNC_START("NapiSessionListener::OnDeviceStateChange");
205 SLOGI("Start handle device state changed event");
206 HandleEvent(EVENT_DEVICE_STATE_CHANGED, deviceState);
207 }
208
AddCallback(napi_env env,int32_t event,napi_value callback)209 napi_status NapiSessionListener::AddCallback(napi_env env, int32_t event, napi_value callback)
210 {
211 std::lock_guard<std::mutex> lockGuard(lock_);
212 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_TYPE_MAX, napi_generic_failure, "has no event");
213 napi_ref ref = nullptr;
214 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
215 napi_generic_failure, "get callback reference failed");
216 CHECK_AND_RETURN_RET_LOG(ref == nullptr, napi_ok, "callback has been registered");
217 napi_status status = napi_create_reference(env, callback, 1, &ref);
218 if (status != napi_ok) {
219 SLOGE("napi_create_reference failed");
220 return status;
221 }
222 if (asyncCallback_ == nullptr) {
223 asyncCallback_ = std::make_shared<NapiAsyncCallback>(env);
224 }
225 callbacks_[event].push_back(ref);
226 SLOGI("add callback %{public}d", static_cast<int32_t>(event));
227 return napi_ok;
228 }
229
RemoveCallback(napi_env env,int32_t event,napi_value callback)230 napi_status NapiSessionListener::RemoveCallback(napi_env env, int32_t event, napi_value callback)
231 {
232 std::lock_guard<std::mutex> lockGuard(lock_);
233 SLOGI("remove callback %{public}d", static_cast<int32_t>(event));
234 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_TYPE_MAX, napi_generic_failure, "has no event");
235 if (callback == nullptr) {
236 for (auto& callbackRef : callbacks_[event]) {
237 napi_status ret = napi_delete_reference(env, callbackRef);
238 CHECK_AND_RETURN_RET_LOG(napi_ok == ret, ret, "delete callback reference failed");
239 callbackRef = nullptr;
240 }
241 callbacks_[event].clear();
242 return napi_ok;
243 }
244 napi_ref ref = nullptr;
245 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
246 napi_generic_failure, "get callback reference failed");
247 CHECK_AND_RETURN_RET_LOG(ref != nullptr, napi_ok, "callback has been remove");
248 callbacks_[event].remove(ref);
249 return napi_delete_reference(env, ref);
250 }
251
GetCallbackNum(int32_t event)252 int32_t NapiSessionListener::GetCallbackNum(int32_t event)
253 {
254 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_TYPE_MAX, 0, "has no event");
255 return callbacks_[event].size();
256 }
257 }