1 /*
2 * Copyright (c) 2023-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_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 if (dataSrcRef_ != nullptr) {
36 napi_ref ref = dataSrcRef_;
37 dataSrcRef_ = nullptr;
38 napi_delete_reference(env_, ref);
39 }
40 SLOGI("destroy");
41 }
42
HandleEvent(int32_t event)43 void NapiAVCastControllerCallback::HandleEvent(int32_t event)
44 {
45 std::lock_guard<std::mutex> lockGuard(lock_);
46 if (callbacks_[event].empty()) {
47 SLOGE("not register callback event=%{public}d", event);
48 return;
49 }
50 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
51 asyncCallback_->Call(*ref);
52 }
53 }
54
CheckCallbackValid(int32_t event,const std::list<napi_ref>::iterator & ref)55 std::function<bool()> NapiAVCastControllerCallback::CheckCallbackValid(int32_t event,
56 const std::list<napi_ref>::iterator& ref)
57 {
58 return [this, event, ref]() {
59 std::lock_guard<std::mutex> lockGuard(lock_);
60 if (callbacks_[event].empty()) {
61 SLOGE("checkCallbackValid with empty list for event %{public}d", event);
62 return false;
63 }
64 bool hasFunc = false;
65 for (auto it = callbacks_[event].begin(); it != callbacks_[event].end(); ++it) {
66 hasFunc = (ref == it ? true : hasFunc);
67 }
68 SLOGD("checkCallbackValid return hasFunc %{public}d, %{public}d", hasFunc, event);
69 return hasFunc;
70 };
71 }
72
73 template<typename T>
HandleEvent(int32_t event,const T & param)74 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const T& param)
75 {
76 std::lock_guard<std::mutex> lockGuard(lock_);
77 if (callbacks_[event].empty()) {
78 SLOGE("not register callback event=%{public}d", event);
79 return;
80 }
81 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
82 SLOGI("call with flag for event %{public}d", event);
83 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
84 [param](napi_env env, int& argc, napi_value *argv) {
85 argc = NapiUtils::ARGC_ONE;
86 auto status = NapiUtils::SetValue(env, param, *argv);
87 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
88 });
89 }
90 }
91
92 template<typename T>
HandleEvent(int32_t event,const std::string & firstParam,const T & secondParam)93 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const std::string& firstParam, const T& secondParam)
94 {
95 std::lock_guard<std::mutex> lockGuard(lock_);
96 if (callbacks_[event].empty()) {
97 SLOGE("not register callback event=%{public}d", event);
98 return;
99 }
100 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
101 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
102 [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
103 argc = NapiUtils::ARGC_TWO;
104 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
105 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
106 status = NapiUtils::SetValue(env, secondParam, argv[1]);
107 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
108 });
109 }
110 }
111
112 template<typename T>
HandleEvent(int32_t event,const int32_t firstParam,const T & secondParam)113 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const int32_t firstParam, const T& secondParam)
114 {
115 std::lock_guard<std::mutex> lockGuard(lock_);
116 if (callbacks_[event].empty()) {
117 SLOGE("not register callback event=%{public}d", event);
118 return;
119 }
120 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
121 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
122 [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
123 argc = NapiUtils::ARGC_TWO;
124 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
125 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
126 status = NapiUtils::SetValue(env, secondParam, argv[1]);
127 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
128 });
129 }
130 }
131
HandleEvent(int32_t event,const int32_t firstParam,const int32_t secondParam,const int32_t thirdParam)132 void NapiAVCastControllerCallback::HandleEvent(int32_t event,
133 const int32_t firstParam, const int32_t secondParam, const int32_t thirdParam)
134 {
135 std::lock_guard<std::mutex> lockGuard(lock_);
136 if (callbacks_[event].empty()) {
137 SLOGE("not register callback event=%{public}d", event);
138 return;
139 }
140 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
141 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
142 [firstParam, secondParam, thirdParam](napi_env env, int& argc, napi_value *argv) {
143 argc = NapiUtils::ARGC_THREE;
144 auto status = NapiUtils::SetValue(env, firstParam, argv[NapiUtils::ARGV_FIRST]);
145 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
146 status = NapiUtils::SetValue(env, secondParam, argv[NapiUtils::ARGV_SECOND]);
147 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
148 status = NapiUtils::SetValue(env, thirdParam, argv[NapiUtils::ARGV_THIRD]);
149 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
150 });
151 }
152 }
153
HandleErrorEvent(int32_t event,const int32_t errorCode,const std::string & errorMsg)154 void NapiAVCastControllerCallback::HandleErrorEvent(int32_t event, const int32_t errorCode,
155 const std::string& errorMsg)
156 {
157 std::lock_guard<std::mutex> lockGuard(lock_);
158 if (callbacks_[event].empty()) {
159 SLOGE("not register callback event=%{public}d", event);
160 return;
161 }
162 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
163 asyncCallback_->CallWithFunc(*ref, isValid_, CheckCallbackValid(event, ref),
164 [errorCode, errorMsg](napi_env env, int& argc, napi_value *argv) {
165 napi_status status = napi_create_object(env, argv);
166 CHECK_RETURN_VOID((status == napi_ok) && (argv != nullptr), "create object failed");
167
168 napi_value property = nullptr;
169 status = NapiUtils::SetValue(env, errorCode, property);
170 CHECK_RETURN_VOID((status == napi_ok) && (property != nullptr), "create property failed");
171 status = napi_set_named_property(env, *argv, "code", property);
172 CHECK_RETURN_VOID(status == napi_ok, "napi_set_named_property failed");
173
174 status = NapiUtils::SetValue(env, errorMsg, property);
175 CHECK_RETURN_VOID((status == napi_ok) && (property != nullptr), "create property failed");
176 status = napi_set_named_property(env, *argv, "message", property);
177 CHECK_RETURN_VOID(status == napi_ok, "napi_set_named_property failed");
178 });
179 }
180 }
181
OnCastPlaybackStateChange(const AVPlaybackState & state)182 void NapiAVCastControllerCallback::OnCastPlaybackStateChange(const AVPlaybackState& state)
183 {
184 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnCastPlaybackStateChange");
185 SLOGI("Start handle OnCastPlaybackStateChange event with state: %{public}d", state.GetState());
186 HandleEvent(EVENT_CAST_PLAYBACK_STATE_CHANGE, state);
187 }
188
OnMediaItemChange(const AVQueueItem & avQueueItem)189 void NapiAVCastControllerCallback::OnMediaItemChange(const AVQueueItem& avQueueItem)
190 {
191 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnMediaItemChange");
192 SLOGI("Start handle OnMediaItemChange event");
193 HandleEvent(EVENT_CAST_MEDIA_ITEM_CHANGE, avQueueItem);
194 }
195
OnCustomData(const AAFwk::WantParams & data)196 void NapiAVCastControllerCallback::OnCustomData(const AAFwk::WantParams& data)
197 {
198 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnCustomData");
199 SLOGI("Start handle OnCustomData event");
200 HandleEvent(EVENT_CAST_CUSTOM_DATA, data);
201 }
202
OnPlayNext()203 void NapiAVCastControllerCallback::OnPlayNext()
204 {
205 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayNext");
206 SLOGI("Start handle OnPlayNext event");
207 HandleEvent(EVENT_CAST_PLAY_NEXT);
208 }
209
OnPlayPrevious()210 void NapiAVCastControllerCallback::OnPlayPrevious()
211 {
212 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayPrevious");
213 SLOGI("Start handle OnPlayPrevious event");
214 HandleEvent(EVENT_CAST_PLAY_PREVIOUS);
215 }
216
OnSeekDone(const int32_t seekNumber)217 void NapiAVCastControllerCallback::OnSeekDone(const int32_t seekNumber)
218 {
219 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnSeekDone");
220 SLOGI("Start handle OnSeekDone event");
221 HandleEvent(EVENT_CAST_SEEK_DONE, seekNumber);
222 }
223
OnVideoSizeChange(const int32_t width,const int32_t height)224 void NapiAVCastControllerCallback::OnVideoSizeChange(const int32_t width, const int32_t height)
225 {
226 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnVideoSizeChange");
227 SLOGI("Start handle OnVideoSizeChange event");
228 HandleEvent(EVENT_CAST_VIDEO_SIZE_CHANGE, width, height);
229 }
230
HandlePlayerErrorAPI13(const int32_t errorCode,const std::string & errorMsg)231 void NapiAVCastControllerCallback::HandlePlayerErrorAPI13(const int32_t errorCode, const std::string& errorMsg)
232 {
233 CastExtErrCodeAPI13 jsErr;
234 if (CAST_GENERIC_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
235 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
236 // Generic error
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_GENERIC_ERR, static_cast<int32_t>(jsErr), errorMsg);
240 } else if (CAST_IO_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
241 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
242 // Input/Output 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_IO_ERR, static_cast<int32_t>(jsErr), errorMsg);
246 } else if (CAST_PARSING_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
247 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
248 // Content parsing 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_PARSING_ERR, static_cast<int32_t>(jsErr), errorMsg);
252 } else if (CAST_DECODE_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
253 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
254 // Decoding 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_DECOD_EERR, static_cast<int32_t>(jsErr), errorMsg);
258 } else if (CAST_RENDER_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
259 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
260 // AudioRender errors
261 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
262 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
263 HandleErrorEvent(EVENT_CAST_RENDER_ERR, static_cast<int32_t>(jsErr), errorMsg);
264 } else if (CAST_DRM_ERRCODE_INFOS.count(static_cast<CastErrCode>(errorCode)) != 0 &&
265 CASTERRCODE_TO_EXTERRORCODEAPI13.count(static_cast<CastErrCode>(errorCode)) != 0) {
266 // DRM errors
267 jsErr = CASTERRCODE_TO_EXTERRORCODEAPI13.at(static_cast<CastErrCode>(errorCode));
268 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
269 HandleErrorEvent(EVENT_CAST_DRM_ERR, static_cast<int32_t>(jsErr), errorMsg);
270 } else {
271 SLOGW("Can not match error code, use default");
272 // If error not in map, need add error and should not return default ERROR_CODE_UNSPECIFIED.
273 jsErr = CAST_GENERICERR_EXT_API13_UNSPECIFIED;
274 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
275 HandleErrorEvent(EVENT_CAST_GENERIC_ERR, static_cast<int32_t>(jsErr), errorMsg);
276 }
277 }
278
OnPlayerError(const int32_t errorCode,const std::string & errorMsg)279 void NapiAVCastControllerCallback::OnPlayerError(const int32_t errorCode, const std::string& errorMsg)
280 {
281 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayerError");
282 SLOGI("Start handle OnPlayerError event");
283 if (static_cast<MediaServiceErrCode>(errorCode) >= MSERR_NO_MEMORY &&
284 static_cast<MediaServiceErrCode>(errorCode) <= MSERR_EXTEND_START) {
285 MediaServiceExtErrCodeAPI9 jsErr;
286 if (MSERRCODE_INFOS.count(static_cast<MediaServiceErrCode>(errorCode)) != 0 &&
287 MSERRCODE_TO_EXTERRORCODEAPI9.count(static_cast<MediaServiceErrCode>(errorCode)) != 0) {
288 jsErr = MSERRCODE_TO_EXTERRORCODEAPI9.at(static_cast<MediaServiceErrCode>(errorCode));
289 } else {
290 SLOGW("Can not match error code, use default");
291 // If error not in map, need add error and should not return default MSERR_EXT_API9_IO.
292 jsErr = MSERR_EXT_API9_IO;
293 }
294 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
295 HandleErrorEvent(EVENT_CAST_ERROR, static_cast<int32_t>(jsErr), errorMsg);
296 } else {
297 HandlePlayerErrorAPI13(errorCode, errorMsg);
298 }
299 }
300
OnEndOfStream(const int32_t isLooping)301 void NapiAVCastControllerCallback::OnEndOfStream(const int32_t isLooping)
302 {
303 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnEndOfStream");
304 SLOGI("Start handle OnEndOfStream event");
305 HandleEvent(EVENT_CAST_END_OF_STREAM, isLooping);
306 }
307
OnPlayRequest(const AVQueueItem & avQueueItem)308 void NapiAVCastControllerCallback::OnPlayRequest(const AVQueueItem& avQueueItem)
309 {
310 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayRequest");
311 SLOGI("Start handle OnPlayRequest event");
312 HandleEvent(EVENT_CAST_PLAY_REQUEST, avQueueItem);
313 }
314
OnKeyRequest(const std::string & assetId,const std::vector<uint8_t> & keyRequestData)315 void NapiAVCastControllerCallback::OnKeyRequest(const std::string &assetId, const std::vector<uint8_t> &keyRequestData)
316 {
317 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnKeyRequest");
318 SLOGI("Start handle OnKeyRequest event");
319 HandleEvent(EVENT_CAST_KEY_REQUEST, assetId, keyRequestData);
320 }
321
OnCastValidCommandChanged(const std::vector<int32_t> & cmds)322 void NapiAVCastControllerCallback::OnCastValidCommandChanged(const std::vector<int32_t>& cmds)
323 {
324 SLOGI("Start handle OnValidCommandChanged event. cmd size:%{public}zd", cmds.size());
325 std::vector<std::string> stringCmds = NapiCastControlCommand::ConvertCommands(cmds);
326 HandleEvent(EVENT_CAST_VALID_COMMAND_CHANGED, stringCmds);
327 }
328
onDataSrcRead(const std::shared_ptr<AVSharedMemoryBase> & mem,uint32_t length,int64_t pos,int32_t & result)329 int32_t NapiAVCastControllerCallback::onDataSrcRead(const std::shared_ptr<AVSharedMemoryBase>& mem,
330 uint32_t length, int64_t pos, int32_t& result)
331 {
332 SLOGI("napi onDataSrcRead length %{public}d", length);
333 return readDataSrc(env_, mem, length, pos, result);
334 }
335
saveDataSrc(napi_env env,napi_value avQueueItem)336 napi_status NapiAVCastControllerCallback::saveDataSrc(napi_env env, napi_value avQueueItem)
337 {
338 napi_value fileSize;
339 napi_value callback {};
340 napi_status status = NapiQueueItem::GetDataSrc(env, avQueueItem, &fileSize, &callback);
341 CHECK_RETURN(status == napi_ok, "GetDataSrc value failed", status);
342 if (status != napi_ok) {
343 SLOGI("no saveDataSrc, reset");
344 return status;
345 }
346
347 napi_env preEnv = env_;
348 env_ = env;
349 if (dataSrcRef_ != nullptr) {
350 napi_ref ref = dataSrcRef_;
351 dataSrcRef_ = nullptr;
352 napi_delete_reference(preEnv, ref);
353 }
354 status = napi_create_reference(env, callback, 1, &dataSrcRef_);
355 CHECK_RETURN(status == napi_ok, "napi_create_reference failed", status);
356
357 if (threadSafeReadDataSrcFunc_ == nullptr) {
358 napi_value resourceName = nullptr;
359 napi_create_string_utf8(env, "ThreadSafeFunction in NapiAVCastControllerCallback",
360 NAPI_AUTO_LENGTH, &resourceName);
361 napi_create_threadsafe_function(env, nullptr, nullptr, resourceName, 0, 1, nullptr, nullptr,
362 nullptr, threadSafeReadDataSrcCb, &threadSafeReadDataSrcFunc_);
363 }
364 return napi_ok;
365 }
366
threadSafeReadDataSrcCb(napi_env env,napi_value js_cb,void * context,void * data)367 void NapiAVCastControllerCallback::threadSafeReadDataSrcCb(napi_env env, napi_value js_cb, void* context, void* data)
368 {
369 std::shared_ptr<DataContextForThreadSafe> appData(static_cast<DataContextForThreadSafe*>(data),
370 [](DataContextForThreadSafe* ptr) {
371 delete ptr;
372 ptr = nullptr;
373 });
374
375 napi_status status;
376 napi_value global {};
377 napi_get_global(env, &global);
378
379 napi_value callback {};
380 napi_get_reference_value(env, appData->callback, &callback);
381
382 napi_value argv[3] = { nullptr };
383
384 status = napi_create_external_arraybuffer(env, appData->buffer, appData->length,
385 [](napi_env env, void *data, void *hint) {}, nullptr, &argv[NapiUtils::ARGV_FIRST]);
386 CHECK_RETURN_VOID(status == napi_ok, "get napi_create_external_arraybuffer value failed");
387
388 status = napi_create_uint32(env, appData->length, &argv[NapiUtils::ARGV_SECOND]);
389 CHECK_RETURN_VOID(status == napi_ok, "get napi_create_uint32 value failed");
390
391 status = napi_create_int64(env, appData->pos, &argv[NapiUtils::ARGV_THIRD]);
392 CHECK_RETURN_VOID(status == napi_ok, "get napi_create_int64 value failed");
393
394 napi_value result;
395 status = napi_call_function(env, global, callback, NapiUtils::ARGC_THREE, argv, &result);
396 if (status != napi_ok) {
397 SLOGE("call function failed status=%{public}d.", status);
398 }
399 napi_get_value_int32(env, result, appData->result);
400
401 appData->dataSrcSyncCond.notify_one();
402 return;
403 }
404
readDataSrc(napi_env env,const std::shared_ptr<AVSharedMemoryBase> & mem,uint32_t length,int64_t pos,int32_t & result)405 int32_t NapiAVCastControllerCallback::readDataSrc(napi_env env, const std::shared_ptr<AVSharedMemoryBase>& mem,
406 uint32_t length, int64_t pos, int32_t& result)
407 {
408 if (dataSrcRef_ == nullptr) {
409 SLOGE("dataSrcRef_ nullptr");
410 return 0;
411 }
412 DataContextForThreadSafe* data =
413 new DataContextForThreadSafe { dataSrcRef_, mem->GetBase(), length, pos, &result, dataSrcSyncCond_ };
414 napi_status status = napi_call_threadsafe_function(threadSafeReadDataSrcFunc_, data, napi_tsfn_blocking);
415 if (status != napi_ok) {
416 SLOGE("readDataSrc function call failed %{public}d", status);
417 delete data;
418 return 0;
419 }
420
421 std::unique_lock<std::mutex> lock(dataSrcSyncLock_);
422 auto waitStatus = dataSrcSyncCond_.wait_for(lock, std::chrono::milliseconds(500));
423 if (waitStatus == std::cv_status::timeout) {
424 SLOGE("readDataSrc dataSrcSyncCond_ timeout");
425 }
426 SLOGI("readDataSrc result %{public}d", result);
427 return result;
428 }
429
AddCallback(napi_env env,int32_t event,napi_value callback)430 napi_status NapiAVCastControllerCallback::AddCallback(napi_env env, int32_t event, napi_value callback)
431 {
432 std::lock_guard<std::mutex> lockGuard(lock_);
433 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_CAST_TYPE_MAX, napi_generic_failure, "has no event");
434 napi_ref ref = nullptr;
435 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
436 napi_generic_failure, "get callback reference failed");
437 CHECK_AND_RETURN_RET_LOG(ref == nullptr, napi_ok, "callback has been registered");
438 napi_status status = napi_create_reference(env, callback, NapiUtils::ARGC_ONE, &ref);
439 if (status != napi_ok) {
440 SLOGE("napi_create_reference failed");
441 return status;
442 }
443 if (asyncCallback_ == nullptr) {
444 asyncCallback_ = std::make_shared<NapiAsyncCallback>(env);
445 if (asyncCallback_ == nullptr) {
446 SLOGE("no memory");
447 return napi_generic_failure;
448 }
449 }
450 SLOGI("addCallback isValidSet to prevent off, with ref %{public}d", event);
451 callbacks_[event].push_back(ref);
452 if (isValid_ == nullptr) {
453 SLOGI("addCallback with no isValid_ init");
454 isValid_ = std::make_shared<bool>(true);
455 } else {
456 SLOGI("addCallback with isValid_ set true");
457 *isValid_ = true;
458 }
459 return napi_ok;
460 }
461
RemoveCallback(napi_env env,int32_t event,napi_value callback)462 napi_status NapiAVCastControllerCallback::RemoveCallback(napi_env env, int32_t event, napi_value callback)
463 {
464 std::lock_guard<std::mutex> lockGuard(lock_);
465 SLOGI("try remove callback for event %{public}d", event);
466 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_CAST_TYPE_MAX, napi_generic_failure, "has no event");
467 if (callback == nullptr) {
468 SLOGD("Remove callback, the callback is nullptr");
469 for (auto callbackRef = callbacks_[event].begin(); callbackRef != callbacks_[event].end(); ++callbackRef) {
470 napi_status ret = napi_delete_reference(env, *callbackRef);
471 CHECK_AND_RETURN_RET_LOG(ret == napi_ok, ret, "delete callback reference failed");
472 *callbackRef = nullptr;
473 }
474 callbacks_[event].clear();
475 // not remove this logic for play button will not valid when stopcast at media control second page
476 SLOGE("RemoveCallback with isvalid set false when playbackstatechange off");
477 if (event == EVENT_CAST_PLAYBACK_STATE_CHANGE) {
478 if (isValid_ == nullptr) {
479 SLOGE("remove callback with no isValid_ init");
480 return napi_ok;
481 }
482 SLOGI("removeCallback with isValid_ set false");
483 *isValid_ = false;
484 }
485 return napi_ok;
486 }
487 napi_ref ref = nullptr;
488 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
489 napi_generic_failure, "get callback reference failed");
490 SLOGI("remove single callback with ref %{public}d", event);
491 CHECK_AND_RETURN_RET_LOG(ref != nullptr, napi_ok, "callback has been remove");
492 callbacks_[event].remove(ref);
493 return napi_delete_reference(env, ref);
494 }
495
IsCallbacksEmpty(int32_t event)496 bool NapiAVCastControllerCallback::IsCallbacksEmpty(int32_t event)
497 {
498 CHECK_AND_RETURN_RET_LOG(event >= 0 && event < EVENT_CAST_TYPE_MAX, true, "has no event");
499 return callbacks_[event].empty();
500 }
501 } // namespace OHOS::AVSession
502