• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }