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