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 "napi_avsession_callback.h"
17 #include "avsession_log.h"
18 #include "napi_utils.h"
19 #include "avsession_trace.h"
20
21 namespace OHOS::AVSession {
NapiAVSessionCallback()22 NapiAVSessionCallback::NapiAVSessionCallback()
23 {
24 SLOGI("construct NapiAVSessionCallback");
25 isValid_ = std::make_shared<bool>(true);
26 }
27
~NapiAVSessionCallback()28 NapiAVSessionCallback::~NapiAVSessionCallback()
29 {
30 SLOGI("destroy NapiAVSessionCallback");
31 *isValid_ = false;
32 }
33
HandleEvent(int32_t event)34 void NapiAVSessionCallback::HandleEvent(int32_t event)
35 {
36 std::lock_guard<std::mutex> lockGuard(lock_);
37 if (callbacks_[event].empty()) {
38 SLOGE("not register callback event=%{public}d", event);
39 return;
40 }
41 SLOGI("send control command %{public}d to session with callback size %{public}d",
42 event, static_cast<int>(callbacks_[event].size()));
43 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
44 asyncCallback_->CallWithFunc(*ref, isValid_,
45 [this, ref, event]() {
46 std::lock_guard<std::mutex> lockGuard(lock_);
47 if (callbacks_[event].empty()) {
48 SLOGI("checkCallbackValid with empty list for event %{public}d", event);
49 return false;
50 }
51 bool hasFunc = false;
52 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
53 hasFunc = (ref == it ? true : hasFunc);
54 }
55 SLOGD("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
56 return hasFunc;
57 });
58 }
59 }
60
61 template<typename T>
HandleEvent(int32_t event,const T & param)62 void NapiAVSessionCallback::HandleEvent(int32_t event, const T& param)
63 {
64 std::lock_guard<std::mutex> lockGuard(lock_);
65 if (callbacks_[event].empty()) {
66 SLOGE("not register callback event=%{public}d", event);
67 return;
68 }
69 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
70 asyncCallback_->CallWithFunc(*ref, isValid_,
71 [this, ref, event]() {
72 std::lock_guard<std::mutex> lockGuard(lock_);
73 if (callbacks_[event].empty()) {
74 SLOGE("checkCallbackValid with empty list for event=%{public}d", event);
75 return false;
76 }
77 bool hasFunc = false;
78 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
79 hasFunc = (ref == it ? true : hasFunc);
80 }
81 if (!hasFunc) {
82 SLOGE("checkCallbackValid res false for event=%{public}d", event);
83 }
84 return hasFunc;
85 },
86 [param](napi_env env, int& argc, napi_value* argv) {
87 argc = NapiUtils::ARGC_ONE;
88 NapiUtils::SetValue(env, param, *argv);
89 });
90 }
91 }
92
93 template<typename T>
HandleEvent(int32_t event,const std::string & firstParam,const T & secondParam)94 void NapiAVSessionCallback::HandleEvent(int32_t event, const std::string& firstParam, const T& secondParam)
95 {
96 std::lock_guard<std::mutex> lockGuard(lock_);
97 if (callbacks_[event].empty()) {
98 SLOGE("Not register callback event: %{public}d", event);
99 return;
100 }
101 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
102 asyncCallback_->CallWithFunc(*ref, isValid_,
103 [this, ref, event]() {
104 std::lock_guard<std::mutex> lockGuard(lock_);
105 if (callbacks_[event].empty()) {
106 SLOGI("checkCallbackValid with empty list for event %{public}d", event);
107 return false;
108 }
109 bool hasFunc = false;
110 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
111 hasFunc = (ref == it ? true : hasFunc);
112 }
113 SLOGD("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
114 return hasFunc;
115 },
116 [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
117 argc = NapiUtils::ARGC_TWO;
118 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
119 CHECK_RETURN_VOID(status == napi_ok, "AVSessionCallback set first param invalid");
120 status = NapiUtils::SetValue(env, secondParam, argv[1]);
121 CHECK_RETURN_VOID(status == napi_ok, "AVSessionCallback set second param invalid");
122 });
123 }
124 }
125
126 template<typename T>
HandleEvent(int32_t event,const int32_t firstParam,const T & secondParam)127 void NapiAVSessionCallback::HandleEvent(int32_t event, const int32_t firstParam, const T& secondParam)
128 {
129 std::lock_guard<std::mutex> lockGuard(lock_);
130 if (callbacks_[event].empty()) {
131 SLOGE("Not register callback event: %{public}d", event);
132 return;
133 }
134 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
135 asyncCallback_->CallWithFunc(*ref, isValid_,
136 [this, ref, event]() {
137 std::lock_guard<std::mutex> lockGuard(lock_);
138 if (callbacks_[event].empty()) {
139 SLOGI("checkCallbackValid with empty list for event %{public}d", event);
140 return false;
141 }
142 bool hasFunc = false;
143 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
144 hasFunc = (ref == it ? true : hasFunc);
145 }
146 SLOGD("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
147 return hasFunc;
148 },
149 [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
150 argc = NapiUtils::ARGC_TWO;
151 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
152 CHECK_RETURN_VOID(status == napi_ok, "AVSessionCallback set first param invalid");
153 status = NapiUtils::SetValue(env, secondParam, argv[1]);
154 CHECK_RETURN_VOID(status == napi_ok, "AVSessionCallback set second param invalid");
155 });
156 }
157 }
158
OnPlay()159 void NapiAVSessionCallback::OnPlay()
160 {
161 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnPlay");
162 HandleEvent(EVENT_PLAY);
163 }
164
OnPause()165 void NapiAVSessionCallback::OnPause()
166 {
167 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnPause");
168 HandleEvent(EVENT_PAUSE);
169 }
170
OnStop()171 void NapiAVSessionCallback::OnStop()
172 {
173 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnStop");
174 HandleEvent(EVENT_STOP);
175 }
176
OnPlayNext()177 void NapiAVSessionCallback::OnPlayNext()
178 {
179 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnPlayNext");
180 HandleEvent(EVENT_PLAY_NEXT);
181 }
182
OnPlayPrevious()183 void NapiAVSessionCallback::OnPlayPrevious()
184 {
185 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnPlayPrevious");
186 HandleEvent(EVENT_PLAY_PREVIOUS);
187 }
188
OnFastForward(int64_t time)189 void NapiAVSessionCallback::OnFastForward(int64_t time)
190 {
191 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnFastForward");
192 HandleEvent(EVENT_FAST_FORWARD, time);
193 }
194
OnRewind(int64_t time)195 void NapiAVSessionCallback::OnRewind(int64_t time)
196 {
197 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnRewind");
198 HandleEvent(EVENT_REWIND, time);
199 }
200
OnSeek(int64_t time)201 void NapiAVSessionCallback::OnSeek(int64_t time)
202 {
203 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnSeek");
204 HandleEvent(EVENT_SEEK, time);
205 }
206
OnSetSpeed(double speed)207 void NapiAVSessionCallback::OnSetSpeed(double speed)
208 {
209 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnSetSpeed");
210 HandleEvent(EVENT_SET_SPEED, speed);
211 }
212
OnSetLoopMode(int32_t loopMode)213 void NapiAVSessionCallback::OnSetLoopMode(int32_t loopMode)
214 {
215 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnSetLoopMode");
216 if (loopMode == AVPlaybackState::LOOP_MODE_UNDEFINED) {
217 HandleEvent(EVENT_SET_LOOP_MODE);
218 } else {
219 HandleEvent(EVENT_SET_LOOP_MODE, loopMode);
220 }
221 }
222
OnSetTargetLoopMode(int32_t targetLoopMode)223 void NapiAVSessionCallback::OnSetTargetLoopMode(int32_t targetLoopMode)
224 {
225 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnSetTargetLoopMode");
226 if (targetLoopMode == AVPlaybackState::LOOP_MODE_UNDEFINED) {
227 HandleEvent(EVENT_SET_TARGET_LOOP_MODE);
228 } else {
229 HandleEvent(EVENT_SET_TARGET_LOOP_MODE, targetLoopMode);
230 }
231 }
232
OnToggleFavorite(const std::string & assertId)233 void NapiAVSessionCallback::OnToggleFavorite(const std::string& assertId)
234 {
235 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnToggleFavorite");
236 HandleEvent(EVENT_TOGGLE_FAVORITE, assertId);
237 }
238
OnCustomData(const AAFwk::WantParams & data)239 void NapiAVSessionCallback::OnCustomData(const AAFwk::WantParams& data)
240 {
241 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnCustomData");
242 HandleEvent(EVENT_CUSTOM_DATA, data);
243 }
244
OnMediaKeyEvent(const MMI::KeyEvent & keyEvent)245 void NapiAVSessionCallback::OnMediaKeyEvent(const MMI::KeyEvent& keyEvent)
246 {
247 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnMediaKeyEvent");
248 HandleEvent(EVENT_MEDIA_KEY_EVENT, std::make_shared<MMI::KeyEvent>(keyEvent));
249 }
250
OnOutputDeviceChange(const int32_t connectionState,const OutputDeviceInfo & outputDeviceInfo)251 void NapiAVSessionCallback::OnOutputDeviceChange(const int32_t connectionState,
252 const OutputDeviceInfo& outputDeviceInfo)
253 {
254 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnOutputDeviceChange");
255 SLOGI("OnOutputDeviceChange with connectionState %{public}d", connectionState);
256 HandleEvent(EVENT_OUTPUT_DEVICE_CHANGE, connectionState, outputDeviceInfo);
257 }
258
OnCommonCommand(const std::string & commonCommand,const AAFwk::WantParams & commandArgs)259 void NapiAVSessionCallback::OnCommonCommand(const std::string& commonCommand, const AAFwk::WantParams& commandArgs)
260 {
261 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnCommonCommand");
262 HandleEvent(EVENT_SEND_COMMON_COMMAND, commonCommand, commandArgs);
263 }
264
OnSkipToQueueItem(int32_t itemId)265 void NapiAVSessionCallback::OnSkipToQueueItem(int32_t itemId)
266 {
267 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnSkipToQueueItem");
268 HandleEvent(EVENT_SKIP_TO_QUEUE_ITEM, itemId);
269 }
270
OnAVCallAnswer()271 void NapiAVSessionCallback::OnAVCallAnswer()
272 {
273 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnAnswer");
274 HandleEvent(EVENT_AVCALL_ANSWER);
275 }
276
OnAVCallHangUp()277 void NapiAVSessionCallback::OnAVCallHangUp()
278 {
279 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnHangUp");
280 HandleEvent(EVENT_AVCALL_HANG_UP);
281 }
282
OnAVCallToggleCallMute()283 void NapiAVSessionCallback::OnAVCallToggleCallMute()
284 {
285 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnToggleCallMute");
286 HandleEvent(EVENT_AVCALL_TOGGLE_CALL_MUTE);
287 }
288
OnPlayFromAssetId(int64_t assetId)289 void NapiAVSessionCallback::OnPlayFromAssetId(int64_t assetId)
290 {
291 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnPlayFromAssetId");
292 HandleEvent(EVENT_PLAY_FROM_ASSETID, assetId);
293 }
294
OnPlayWithAssetId(const std::string & assetId)295 void NapiAVSessionCallback::OnPlayWithAssetId(const std::string& assetId)
296 {
297 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnPlayWithAssetId");
298 HandleEvent(EVENT_PLAY_WITH_ASSETID, assetId);
299 }
300
OnCastDisplayChange(const CastDisplayInfo & castDisplayInfo)301 void NapiAVSessionCallback::OnCastDisplayChange(const CastDisplayInfo& castDisplayInfo)
302 {
303 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnCastDisplayChange");
304 HandleEvent(EVENT_DISPLAY_CHANGE, castDisplayInfo);
305 }
306
OnCastDisplaySizeChange(const CastDisplayInfo & castDisplayInfo)307 void NapiAVSessionCallback::OnCastDisplaySizeChange(const CastDisplayInfo& castDisplayInfo)
308 {
309 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnCastDisplaySizeChange");
310 HandleEvent(EVENT_DISPLAY_CHANGE, castDisplayInfo);
311 }
312
AddCallback(napi_env env,int32_t event,napi_value callback)313 napi_status NapiAVSessionCallback::AddCallback(napi_env env, int32_t event, napi_value callback)
314 {
315 SLOGI("Add callback %{public}d", event);
316 std::lock_guard<std::mutex> lockGuard(lock_);
317 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_TYPE_MAX, napi_generic_failure, "has no event");
318 napi_ref ref = nullptr;
319 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
320 napi_generic_failure, "get callback reference failed");
321 CHECK_AND_RETURN_RET_LOG(ref == nullptr, napi_ok, "callback has been registered");
322 napi_status status = napi_create_reference(env, callback, NapiUtils::ARGC_ONE, &ref);
323 if (status != napi_ok) {
324 SLOGE("napi_create_reference failed");
325 return status;
326 }
327 if (asyncCallback_ == nullptr) {
328 asyncCallback_ = std::make_shared<NapiAsyncCallback>(env);
329 if (asyncCallback_ == nullptr) {
330 SLOGE("no memory");
331 return napi_generic_failure;
332 }
333 }
334 callbacks_[event].push_back(ref);
335 return napi_ok;
336 }
337
RemoveCallback(napi_env env,int32_t event,napi_value callback)338 napi_status NapiAVSessionCallback::RemoveCallback(napi_env env, int32_t event, napi_value callback)
339 {
340 SLOGI("Remove callback %{public}d", event);
341 std::lock_guard<std::mutex> lockGuard(lock_);
342 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_TYPE_MAX, napi_generic_failure, "has no event");
343 if (callback == nullptr) {
344 for (auto callbackRef = callbacks_[event].begin(); callbackRef != callbacks_[event].end(); ++callbackRef) {
345 napi_status ret = napi_delete_reference(env, *callbackRef);
346 CHECK_AND_RETURN_RET_LOG(napi_ok == ret, ret, "delete callback reference failed");
347 }
348 callbacks_[event].clear();
349 return napi_ok;
350 }
351 napi_ref ref = nullptr;
352 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
353 napi_generic_failure, "get callback reference failed");
354 CHECK_AND_RETURN_RET_LOG(ref != nullptr, napi_ok, "callback has been remove");
355 callbacks_[event].remove(ref);
356 return napi_delete_reference(env, ref);
357 }
358
IsCallbacksEmpty(int32_t event)359 bool NapiAVSessionCallback::IsCallbacksEmpty(int32_t event)
360 {
361 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_TYPE_MAX, true, "has no event");
362 return callbacks_[event].empty();
363 }
364 }
365