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