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