• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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