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