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 "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
OnMediaKeyEvent(const MMI::KeyEvent & keyEvent)239 void NapiAVSessionCallback::OnMediaKeyEvent(const MMI::KeyEvent& keyEvent)
240 {
241 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnMediaKeyEvent");
242 HandleEvent(EVENT_MEDIA_KEY_EVENT, std::make_shared<MMI::KeyEvent>(keyEvent));
243 }
244
OnOutputDeviceChange(const int32_t connectionState,const OutputDeviceInfo & outputDeviceInfo)245 void NapiAVSessionCallback::OnOutputDeviceChange(const int32_t connectionState,
246 const OutputDeviceInfo& outputDeviceInfo)
247 {
248 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnOutputDeviceChange");
249 SLOGI("OnOutputDeviceChange with connectionState %{public}d", connectionState);
250 HandleEvent(EVENT_OUTPUT_DEVICE_CHANGE, connectionState, outputDeviceInfo);
251 }
252
OnCommonCommand(const std::string & commonCommand,const AAFwk::WantParams & commandArgs)253 void NapiAVSessionCallback::OnCommonCommand(const std::string& commonCommand, const AAFwk::WantParams& commandArgs)
254 {
255 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnCommonCommand");
256 HandleEvent(EVENT_SEND_COMMON_COMMAND, commonCommand, commandArgs);
257 }
258
OnSkipToQueueItem(int32_t itemId)259 void NapiAVSessionCallback::OnSkipToQueueItem(int32_t itemId)
260 {
261 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnSkipToQueueItem");
262 HandleEvent(EVENT_SKIP_TO_QUEUE_ITEM, itemId);
263 }
264
OnAVCallAnswer()265 void NapiAVSessionCallback::OnAVCallAnswer()
266 {
267 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnAnswer");
268 HandleEvent(EVENT_AVCALL_ANSWER);
269 }
270
OnAVCallHangUp()271 void NapiAVSessionCallback::OnAVCallHangUp()
272 {
273 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnHangUp");
274 HandleEvent(EVENT_AVCALL_HANG_UP);
275 }
276
OnAVCallToggleCallMute()277 void NapiAVSessionCallback::OnAVCallToggleCallMute()
278 {
279 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnToggleCallMute");
280 HandleEvent(EVENT_AVCALL_TOGGLE_CALL_MUTE);
281 }
282
OnPlayFromAssetId(int64_t assetId)283 void NapiAVSessionCallback::OnPlayFromAssetId(int64_t assetId)
284 {
285 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnPlayFromAssetId");
286 HandleEvent(EVENT_PLAY_FROM_ASSETID, assetId);
287 }
288
OnCastDisplayChange(const CastDisplayInfo & castDisplayInfo)289 void NapiAVSessionCallback::OnCastDisplayChange(const CastDisplayInfo& castDisplayInfo)
290 {
291 AVSESSION_TRACE_SYNC_START("NapiAVSessionCallback::OnCastDisplayChange");
292 HandleEvent(EVENT_DISPLAY_CHANGE, castDisplayInfo);
293 }
294
AddCallback(napi_env env,int32_t event,napi_value callback)295 napi_status NapiAVSessionCallback::AddCallback(napi_env env, int32_t event, napi_value callback)
296 {
297 SLOGI("Add callback %{public}d", event);
298 std::lock_guard<std::mutex> lockGuard(lock_);
299 napi_ref ref = nullptr;
300 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
301 napi_generic_failure, "get callback reference failed");
302 CHECK_AND_RETURN_RET_LOG(ref == nullptr, napi_ok, "callback has been registered");
303 napi_status status = napi_create_reference(env, callback, NapiUtils::ARGC_ONE, &ref);
304 if (status != napi_ok) {
305 SLOGE("napi_create_reference failed");
306 return status;
307 }
308 if (asyncCallback_ == nullptr) {
309 asyncCallback_ = std::make_shared<NapiAsyncCallback>(env);
310 if (asyncCallback_ == nullptr) {
311 SLOGE("no memory");
312 return napi_generic_failure;
313 }
314 }
315 callbacks_[event].push_back(ref);
316 return napi_ok;
317 }
318
RemoveCallback(napi_env env,int32_t event,napi_value callback)319 napi_status NapiAVSessionCallback::RemoveCallback(napi_env env, int32_t event, napi_value callback)
320 {
321 SLOGI("Remove callback %{public}d", event);
322 std::lock_guard<std::mutex> lockGuard(lock_);
323 if (callback == nullptr) {
324 for (auto callbackRef = callbacks_[event].begin(); callbackRef != callbacks_[event].end(); ++callbackRef) {
325 napi_status ret = napi_delete_reference(env, *callbackRef);
326 CHECK_AND_RETURN_RET_LOG(napi_ok == ret, ret, "delete callback reference failed");
327 }
328 callbacks_[event].clear();
329 return napi_ok;
330 }
331 napi_ref ref = nullptr;
332 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
333 napi_generic_failure, "get callback reference failed");
334 CHECK_AND_RETURN_RET_LOG(ref != nullptr, napi_ok, "callback has been remove");
335 callbacks_[event].remove(ref);
336 return napi_delete_reference(env, ref);
337 }
338
IsCallbacksEmpty(int32_t event)339 bool NapiAVSessionCallback::IsCallbacksEmpty(int32_t event)
340 {
341 return callbacks_[event].empty();
342 }
343 }
344