1 /*
2 * Copyright (c) 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_avcast_controller_callback.h"
17 #include "avsession_log.h"
18 #include "avsession_trace.h"
19 #include "napi_control_command.h"
20 #include "napi_meta_data.h"
21 #include "napi_playback_state.h"
22 #include "napi_media_description.h"
23 #include "napi_queue_item.h"
24 #include "napi_utils.h"
25 #include "napi_cast_control_command.h"
26
27 namespace OHOS::AVSession {
NapiAVCastControllerCallback()28 NapiAVCastControllerCallback::NapiAVCastControllerCallback()
29 {
30 SLOGI("construct");
31 }
32
~NapiAVCastControllerCallback()33 NapiAVCastControllerCallback::~NapiAVCastControllerCallback()
34 {
35 SLOGI("destroy");
36 }
37
HandleEvent(int32_t event)38 void NapiAVCastControllerCallback::HandleEvent(int32_t event)
39 {
40 std::lock_guard<std::mutex> lockGuard(lock_);
41 if (callbacks_[event].empty()) {
42 SLOGE("not register callback event=%{public}d", event);
43 return;
44 }
45 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
46 asyncCallback_->Call(*ref);
47 }
48 }
49
CheckCallbackValid(int32_t event,const std::list<napi_ref>::iterator & ref)50 std::function<bool()> NapiAVCastControllerCallback::CheckCallbackValid(int32_t event,
51 const std::list<napi_ref>::iterator& ref)
52 {
53 return [this, event, ref]() {
54 std::lock_guard<std::mutex> lockGuard(lock_);
55 if (callbacks_[event].empty()) {
56 SLOGE("checkCallbackValid with empty list for event %{public}d", event);
57 return false;
58 }
59 bool hasFunc = false;
60 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
61 hasFunc = (ref == it ? true : hasFunc);
62 }
63 SLOGI("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
64 return hasFunc;
65 };
66 }
67
68 template<typename T>
HandleEvent(int32_t event,const T & param)69 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const T& param)
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_, CheckCallbackValid(event, ref),
79 [param](napi_env env, int& argc, napi_value *argv) {
80 argc = NapiUtils::ARGC_ONE;
81 auto status = NapiUtils::SetValue(env, param, *argv);
82 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
83 });
84 }
85 }
86
87 template<typename T>
HandleEvent(int32_t event,const std::string & firstParam,const T & secondParam)88 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const std::string& firstParam, const T& secondParam)
89 {
90 std::lock_guard<std::mutex> lockGuard(lock_);
91 if (callbacks_[event].empty()) {
92 SLOGE("not register callback event=%{public}d", event);
93 return;
94 }
95 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
96 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
97 [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
98 argc = NapiUtils::ARGC_TWO;
99 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
100 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
101 status = NapiUtils::SetValue(env, secondParam, argv[1]);
102 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
103 });
104 }
105 }
106
107 template<typename T>
HandleEvent(int32_t event,const int32_t firstParam,const T & secondParam)108 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const int32_t firstParam, const T& secondParam)
109 {
110 std::lock_guard<std::mutex> lockGuard(lock_);
111 if (callbacks_[event].empty()) {
112 SLOGE("not register callback event=%{public}d", event);
113 return;
114 }
115 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
116 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
117 [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
118 argc = NapiUtils::ARGC_TWO;
119 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
120 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
121 status = NapiUtils::SetValue(env, secondParam, argv[1]);
122 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
123 });
124 }
125 }
126
HandleEvent(int32_t event,const int32_t firstParam,const int32_t secondParam,const int32_t thirdParam)127 void NapiAVCastControllerCallback::HandleEvent(int32_t event,
128 const int32_t firstParam, const int32_t secondParam, const int32_t thirdParam)
129 {
130 std::lock_guard<std::mutex> lockGuard(lock_);
131 if (callbacks_[event].empty()) {
132 SLOGE("not register callback event=%{public}d", event);
133 return;
134 }
135 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
136 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
137 [firstParam, secondParam, thirdParam](napi_env env, int& argc, napi_value *argv) {
138 argc = NapiUtils::ARGC_THREE;
139 auto status = NapiUtils::SetValue(env, firstParam, argv[NapiUtils::ARGV_FIRST]);
140 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
141 status = NapiUtils::SetValue(env, secondParam, argv[NapiUtils::ARGV_SECOND]);
142 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
143 status = NapiUtils::SetValue(env, thirdParam, argv[NapiUtils::ARGV_THIRD]);
144 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
145 });
146 }
147 }
148
HandleErrorEvent(int32_t event,const int32_t errorCode,const std::string & errorMsg)149 void NapiAVCastControllerCallback::HandleErrorEvent(int32_t event, const int32_t errorCode,
150 const std::string& errorMsg)
151 {
152 std::lock_guard<std::mutex> lockGuard(lock_);
153 if (callbacks_[event].empty()) {
154 SLOGE("not register callback event=%{public}d", event);
155 return;
156 }
157 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
158 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
159 [errorCode, errorMsg](napi_env env, int& argc, napi_value *argv) {
160 napi_status status = napi_create_object(env, argv);
161 CHECK_RETURN_VOID((status == napi_ok) && (argv != nullptr), "create object failed");
162
163 napi_value property = nullptr;
164 status = NapiUtils::SetValue(env, errorCode, property);
165 CHECK_RETURN_VOID((status == napi_ok) && (property != nullptr), "create property failed");
166 status = napi_set_named_property(env, *argv, "code", property);
167 CHECK_RETURN_VOID(status == napi_ok, "napi_set_named_property failed");
168
169 status = NapiUtils::SetValue(env, errorMsg, property);
170 CHECK_RETURN_VOID((status == napi_ok) && (property != nullptr), "create property failed");
171 status = napi_set_named_property(env, *argv, "message", property);
172 CHECK_RETURN_VOID(status == napi_ok, "napi_set_named_property failed");
173 });
174 }
175 }
176
OnCastPlaybackStateChange(const AVPlaybackState & state)177 void NapiAVCastControllerCallback::OnCastPlaybackStateChange(const AVPlaybackState& state)
178 {
179 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnCastPlaybackStateChange");
180 SLOGI("Start handle OnCastPlaybackStateChange event with state: %{public}d", state.GetState());
181 HandleEvent(EVENT_CAST_PLAYBACK_STATE_CHANGE, state);
182 }
183
OnMediaItemChange(const AVQueueItem & avQueueItem)184 void NapiAVCastControllerCallback::OnMediaItemChange(const AVQueueItem& avQueueItem)
185 {
186 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnMediaItemChange");
187 SLOGI("Start handle OnMediaItemChange event");
188 HandleEvent(EVENT_CAST_MEDIA_ITEM_CHANGE, avQueueItem);
189 }
190
OnPlayNext()191 void NapiAVCastControllerCallback::OnPlayNext()
192 {
193 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayNext");
194 SLOGI("Start handle OnPlayNext event");
195 HandleEvent(EVENT_CAST_PLAY_NEXT);
196 }
197
OnPlayPrevious()198 void NapiAVCastControllerCallback::OnPlayPrevious()
199 {
200 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayPrevious");
201 SLOGI("Start handle OnPlayPrevious event");
202 HandleEvent(EVENT_CAST_PLAY_PREVIOUS);
203 }
204
OnSeekDone(const int32_t seekNumber)205 void NapiAVCastControllerCallback::OnSeekDone(const int32_t seekNumber)
206 {
207 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnSeekDone");
208 SLOGI("Start handle OnSeekDone event");
209 HandleEvent(EVENT_CAST_SEEK_DONE, seekNumber);
210 }
211
OnVideoSizeChange(const int32_t width,const int32_t height)212 void NapiAVCastControllerCallback::OnVideoSizeChange(const int32_t width, const int32_t height)
213 {
214 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnVideoSizeChange");
215 SLOGI("Start handle OnVideoSizeChange event");
216 HandleEvent(EVENT_CAST_VIDEO_SIZE_CHANGE, width, height);
217 }
218
HandlePlayerErrorAPI13(const int32_t errorCode,const std::string & errorMsg)219 void NapiAVCastControllerCallback::HandlePlayerErrorAPI13(const int32_t errorCode, const std::string& errorMsg)
220 {
221 CastExtErrCodeAPI13 jsErr;
222 if (CAST_GENERIC_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
223 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
224 // Generic error
225 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
226 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
227 HandleErrorEvent(EVENT_CAST_GENERIC_ERR, static_cast<int32_t>(jsErr), errorMsg);
228 } else if (CAST_IO_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
229 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
230 // Input/Output errors
231 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
232 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
233 HandleErrorEvent(EVENT_CAST_IO_ERR, static_cast<int32_t>(jsErr), errorMsg);
234 } else if (CAST_PARSING_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
235 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
236 // Content parsing errors
237 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
238 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
239 HandleErrorEvent(EVENT_CAST_PARSING_ERR, static_cast<int32_t>(jsErr), errorMsg);
240 } else if (CAST_DECODE_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
241 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
242 // Decoding errors
243 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
244 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
245 HandleErrorEvent(EVENT_CAST_DECOD_EERR, static_cast<int32_t>(jsErr), errorMsg);
246 } else if (CAST_RENDER_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
247 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
248 // AudioRender errors
249 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
250 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
251 HandleErrorEvent(EVENT_CAST_RENDER_ERR, static_cast<int32_t>(jsErr), errorMsg);
252 } else if (CAST_DRM_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
253 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
254 // DRM errors
255 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
256 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
257 HandleErrorEvent(EVENT_CAST_DRM_ERR, static_cast<int32_t>(jsErr), errorMsg);
258 } else {
259 SLOGW("Can not match error code, use default");
260 // If error not in map, need add error and should not return default ERROR_CODE_UNSPECIFIED.
261 jsErr = CAST_GENERICERR_EXT_API13_UNSPECIFIED;
262 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
263 HandleErrorEvent(EVENT_CAST_GENERIC_ERR, static_cast<int32_t>(jsErr), errorMsg);
264 }
265 }
266
OnPlayerError(const int32_t errorCode,const std::string & errorMsg)267 void NapiAVCastControllerCallback::OnPlayerError(const int32_t errorCode, const std::string& errorMsg)
268 {
269 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayerError");
270 SLOGI("Start handle OnPlayerError event");
271 if (static_cast<MediaServiceErrCode>(errorCode) >= MSERR_NO_MEMORY &&
272 static_cast<MediaServiceErrCode>(errorCode) <= MSERR_EXTEND_START) {
273 MediaServiceExtErrCodeAPI9 jsErr;
274 if (MSERRCODE_INFOS.count(static_cast<MediaServiceErrCode>(errorCode)) != 0 &&
275 MSERRCODE_TO_EXTERRORCODEAPI9.count(static_cast<MediaServiceErrCode>(errorCode)) != 0) {
276 jsErr = MSERRCODE_TO_EXTERRORCODEAPI9.at(static_cast<MediaServiceErrCode>(errorCode));
277 } else {
278 SLOGW("Can not match error code, use default");
279 // If error not in map, need add error and should not return default MSERR_EXT_API9_IO.
280 jsErr = MSERR_EXT_API9_IO;
281 }
282 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
283 HandleErrorEvent(EVENT_CAST_ERROR, static_cast<int32_t>(jsErr), errorMsg);
284 } else {
285 HandlePlayerErrorAPI13(errorCode, errorMsg);
286 }
287 }
288
OnEndOfStream(const int32_t isLooping)289 void NapiAVCastControllerCallback::OnEndOfStream(const int32_t isLooping)
290 {
291 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnEndOfStream");
292 SLOGI("Start handle OnEndOfStream event");
293 HandleEvent(EVENT_CAST_END_OF_STREAM, isLooping);
294 }
295
OnPlayRequest(const AVQueueItem & avQueueItem)296 void NapiAVCastControllerCallback::OnPlayRequest(const AVQueueItem& avQueueItem)
297 {
298 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayRequest");
299 SLOGI("Start handle OnPlayRequest event");
300 HandleEvent(EVENT_CAST_PLAY_REQUEST, avQueueItem);
301 }
302
OnKeyRequest(const std::string & assetId,const std::vector<uint8_t> & keyRequestData)303 void NapiAVCastControllerCallback::OnKeyRequest(const std::string &assetId, const std::vector<uint8_t> &keyRequestData)
304 {
305 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnKeyRequest");
306 SLOGI("Start handle OnKeyRequest event");
307 HandleEvent(EVENT_CAST_KEY_REQUEST, assetId, keyRequestData);
308 }
309
OnCastValidCommandChanged(const std::vector<int32_t> & cmds)310 void NapiAVCastControllerCallback::OnCastValidCommandChanged(const std::vector<int32_t>& cmds)
311 {
312 SLOGI("Start handle OnValidCommandChanged event. cmd size:%{public}zd", cmds.size());
313 std::vector<std::string> stringCmds = NapiCastControlCommand::ConvertCommands(cmds);
314 HandleEvent(EVENT_CAST_VALID_COMMAND_CHANGED, stringCmds);
315 }
316
AddCallback(napi_env env,int32_t event,napi_value callback)317 napi_status NapiAVCastControllerCallback::AddCallback(napi_env env, int32_t event, napi_value callback)
318 {
319 std::lock_guard<std::mutex> lockGuard(lock_);
320 napi_ref ref = nullptr;
321
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 registered");
325 napi_status status = napi_create_reference(env, callback, NapiUtils::ARGC_ONE, &ref);
326 if (status != napi_ok) {
327 SLOGE("napi_create_reference failed");
328 return status;
329 }
330 if (asyncCallback_ == nullptr) {
331 asyncCallback_ = std::make_shared<NapiAsyncCallback>(env);
332 if (asyncCallback_ == nullptr) {
333 SLOGE("no memory");
334 return napi_generic_failure;
335 }
336 }
337 SLOGI("addCallback isValidSet to prevent off, with ref %{public}d, %{public}p, %{public}p", event, &ref, *(&ref));
338 callbacks_[event].push_back(ref);
339 if (isValid_ == nullptr) {
340 SLOGI("addCallback with no isValid_ init");
341 isValid_ = std::make_shared<bool>(true);
342 } else {
343 SLOGI("addCallback with isValid_ set true");
344 *isValid_ = true;
345 }
346 return napi_ok;
347 }
348
RemoveCallback(napi_env env,int32_t event,napi_value callback)349 napi_status NapiAVCastControllerCallback::RemoveCallback(napi_env env, int32_t event, napi_value callback)
350 {
351 std::lock_guard<std::mutex> lockGuard(lock_);
352 SLOGI("try remove callback for event %{public}d", event);
353 if (callback == nullptr) {
354 SLOGD("Remove callback, the callback is nullptr");
355 for (auto callbackRef = callbacks_[event].begin(); callbackRef != callbacks_[event].end(); ++callbackRef) {
356 napi_status ret = napi_delete_reference(env, *callbackRef);
357 CHECK_AND_RETURN_RET_LOG(ret == napi_ok, ret, "delete callback reference failed");
358 *callbackRef = nullptr;
359 }
360 callbacks_[event].clear();
361 // not remove this logic for play button will not valid when stopcast at media control second page
362 SLOGE("RemoveCallback with isvalid set false when playbackstatechange off");
363 if (event == EVENT_CAST_PLAYBACK_STATE_CHANGE) {
364 if (isValid_ == nullptr) {
365 SLOGE("remove callback with no isValid_ init");
366 return napi_ok;
367 }
368 SLOGI("removeCallback with isValid_ set false");
369 *isValid_ = false;
370 }
371 return napi_ok;
372 }
373 napi_ref ref = nullptr;
374 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
375 napi_generic_failure, "get callback reference failed");
376 SLOGI("remove single callback with ref %{public}d, %{public}p, %{public}p", event, &ref, *(&ref));
377 CHECK_AND_RETURN_RET_LOG(ref != nullptr, napi_ok, "callback has been remove");
378 callbacks_[event].remove(ref);
379 return napi_delete_reference(env, ref);
380 }
381
IsCallbacksEmpty(int32_t event)382 bool NapiAVCastControllerCallback::IsCallbacksEmpty(int32_t event)
383 {
384 return callbacks_[event].empty();
385 }
386 } // namespace OHOS::AVSession
387