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
26 namespace OHOS::AVSession {
NapiAVCastControllerCallback()27 NapiAVCastControllerCallback::NapiAVCastControllerCallback()
28 {
29 SLOGI("construct");
30 }
31
~NapiAVCastControllerCallback()32 NapiAVCastControllerCallback::~NapiAVCastControllerCallback()
33 {
34 SLOGI("destroy");
35 }
36
HandleEvent(int32_t event)37 void NapiAVCastControllerCallback::HandleEvent(int32_t event)
38 {
39 std::lock_guard<std::mutex> lockGuard(lock_);
40 if (callbacks_[event].empty()) {
41 SLOGE("not register callback event=%{public}d", event);
42 return;
43 }
44 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
45 asyncCallback_->Call(*ref);
46 }
47 }
48
49 template<typename T>
HandleEvent(int32_t event,const T & param)50 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const T& param)
51 {
52 std::lock_guard<std::mutex> lockGuard(lock_);
53 if (callbacks_[event].empty()) {
54 SLOGE("not register callback event=%{public}d", event);
55 return;
56 }
57 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
58 asyncCallback_->Call(*ref, [param](napi_env env, int& argc, napi_value *argv) {
59 argc = NapiUtils::ARGC_ONE;
60 auto status = NapiUtils::SetValue(env, param, *argv);
61 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
62 });
63 }
64 }
65
66 template<typename T>
HandleEvent(int32_t event,const std::string & firstParam,const T & secondParam)67 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const std::string& firstParam, const T& secondParam)
68 {
69 std::lock_guard<std::mutex> lockGuard(lock_);
70 if (callbacks_[event].empty()) {
71 SLOGE("not register callback event=%{public}d", event);
72 return;
73 }
74 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
75 asyncCallback_->Call(*ref, [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
76 argc = NapiUtils::ARGC_TWO;
77 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
78 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
79 status = NapiUtils::SetValue(env, secondParam, argv[1]);
80 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
81 });
82 }
83 }
84
85 template<typename T>
HandleEvent(int32_t event,const int32_t firstParam,const T & secondParam)86 void NapiAVCastControllerCallback::HandleEvent(int32_t event, const int32_t firstParam, const T& secondParam)
87 {
88 std::lock_guard<std::mutex> lockGuard(lock_);
89 if (callbacks_[event].empty()) {
90 SLOGE("not register callback event=%{public}d", event);
91 return;
92 }
93 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
94 asyncCallback_->Call(*ref, [firstParam, secondParam](napi_env env, int& argc, napi_value *argv) {
95 argc = NapiUtils::ARGC_TWO;
96 auto status = NapiUtils::SetValue(env, firstParam, argv[0]);
97 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
98 status = NapiUtils::SetValue(env, secondParam, argv[1]);
99 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
100 });
101 }
102 }
103
HandleEvent(int32_t event,const int32_t firstParam,const int32_t secondParam,const int32_t thirdParam)104 void NapiAVCastControllerCallback::HandleEvent(int32_t event,
105 const int32_t firstParam, const int32_t secondParam, const int32_t thirdParam)
106 {
107 std::lock_guard<std::mutex> lockGuard(lock_);
108 if (callbacks_[event].empty()) {
109 SLOGE("not register callback event=%{public}d", event);
110 return;
111 }
112 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
113 asyncCallback_->Call(*ref, [firstParam, secondParam, thirdParam](napi_env env, int& argc, napi_value *argv) {
114 argc = NapiUtils::ARGC_TWO;
115 auto status = NapiUtils::SetValue(env, firstParam, argv[NapiUtils::ARGV_FIRST]);
116 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
117 status = NapiUtils::SetValue(env, secondParam, argv[NapiUtils::ARGV_SECOND]);
118 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
119 status = NapiUtils::SetValue(env, thirdParam, argv[NapiUtils::ARGV_THIRD]);
120 CHECK_RETURN_VOID(status == napi_ok, "ControllerCallback SetValue invalid");
121 });
122 }
123 }
124
HandleErrorEvent(int32_t event,const int32_t errorCode,const std::string & errorMsg)125 void NapiAVCastControllerCallback::HandleErrorEvent(int32_t event, const int32_t errorCode,
126 const std::string& errorMsg)
127 {
128 std::lock_guard<std::mutex> lockGuard(lock_);
129 if (callbacks_[event].empty()) {
130 SLOGE("not register callback event=%{public}d", event);
131 return;
132 }
133 for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) {
134 asyncCallback_->Call(*ref, [errorCode, errorMsg](napi_env env, int& argc, napi_value *argv) {
135 napi_status status = napi_create_object(env, argv);
136 CHECK_RETURN_VOID((status == napi_ok) && (argv != nullptr), "create object failed");
137
138 napi_value property = nullptr;
139 status = NapiUtils::SetValue(env, errorCode, property);
140 CHECK_RETURN_VOID((status == napi_ok) && (property != nullptr), "create property failed");
141 status = napi_set_named_property(env, *argv, "code", property);
142 CHECK_RETURN_VOID(status == napi_ok, "napi_set_named_property failed");
143
144 status = NapiUtils::SetValue(env, errorMsg, property);
145 CHECK_RETURN_VOID((status == napi_ok) && (property != nullptr), "create property failed");
146 status = napi_set_named_property(env, *argv, "message", property);
147 CHECK_RETURN_VOID(status == napi_ok, "napi_set_named_property failed");
148 });
149 }
150 }
151
OnCastPlaybackStateChange(const AVPlaybackState & state)152 void NapiAVCastControllerCallback::OnCastPlaybackStateChange(const AVPlaybackState& state)
153 {
154 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnCastPlaybackStateChange");
155 SLOGI("Start handle OnCastPlaybackStateChange event");
156 HandleEvent(EVENT_CAST_PLAYBACK_STATE_CHANGE, state);
157 }
158
OnMediaItemChange(const AVQueueItem & avQueueItem)159 void NapiAVCastControllerCallback::OnMediaItemChange(const AVQueueItem& avQueueItem)
160 {
161 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnMediaItemChange");
162 SLOGI("Start handle OnCastPlaybackStateChange event");
163 HandleEvent(EVENT_CAST_MEDIA_ITEM_CHANGE, avQueueItem);
164 }
165
OnPlayNext()166 void NapiAVCastControllerCallback::OnPlayNext()
167 {
168 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayNext");
169 SLOGI("Start handle OnPlayNext event");
170 HandleEvent(EVENT_CAST_PLAY_NEXT);
171 }
172
OnPlayPrevious()173 void NapiAVCastControllerCallback::OnPlayPrevious()
174 {
175 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayPrevious");
176 SLOGI("Start handle OnPlayPrevious event");
177 HandleEvent(EVENT_CAST_PLAY_PREVIOUS);
178 }
179
OnSeekDone(const int32_t seekNumber)180 void NapiAVCastControllerCallback::OnSeekDone(const int32_t seekNumber)
181 {
182 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnSeekDone");
183 SLOGI("Start handle OnSeekDone event");
184 HandleEvent(EVENT_CAST_SEEK_DONE, seekNumber);
185 }
186
OnVideoSizeChange(const int32_t width,const int32_t height)187 void NapiAVCastControllerCallback::OnVideoSizeChange(const int32_t width, const int32_t height)
188 {
189 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnVideoSizeChange");
190 SLOGI("Start handle OnVideoSizeChange event");
191 HandleEvent(EVENT_CAST_VIDEO_SIZE_CHANGE, width, height);
192 }
193
OnPlayerError(const int32_t errorCode,const std::string & errorMsg)194 void NapiAVCastControllerCallback::OnPlayerError(const int32_t errorCode, const std::string& errorMsg)
195 {
196 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnPlayerError");
197 SLOGI("Start handle OnPlayerError event");
198 MediaServiceExtErrCodeAPI9 jsErr;
199 if (MSERRCODE_INFOS.count(static_cast<MediaServiceErrCode>(errorCode)) != 0 &&
200 MSERRCODE_TO_EXTERRORCODEAPI9.count(static_cast<MediaServiceErrCode>(errorCode)) != 0) {
201 jsErr = MSERRCODE_TO_EXTERRORCODEAPI9.at(static_cast<MediaServiceErrCode>(errorCode));
202 } else {
203 SLOGW("Can not match error code, use default");
204 // If error not in map, need add error and should not return default MSERR_EXT_API9_IO.
205 jsErr = MSERR_EXT_API9_IO;
206 }
207 SLOGI("Native errCode: %{public}d, JS errCode: %{public}d", errorCode, static_cast<int32_t>(jsErr));
208 HandleErrorEvent(EVENT_CAST_ERROR, static_cast<int32_t>(jsErr), errorMsg);
209 }
210
OnEndOfStream(const int32_t isLooping)211 void NapiAVCastControllerCallback::OnEndOfStream(const int32_t isLooping)
212 {
213 AVSESSION_TRACE_SYNC_START("NapiAVCastControllerCallback::OnEndOfStream");
214 SLOGI("Start handle OnEndOfStream event");
215 HandleEvent(EVENT_CAST_END_OF_STREAM, isLooping);
216 }
217
AddCallback(napi_env env,int32_t event,napi_value callback)218 napi_status NapiAVCastControllerCallback::AddCallback(napi_env env, int32_t event, napi_value callback)
219 {
220 std::lock_guard<std::mutex> lockGuard(lock_);
221 napi_ref ref = nullptr;
222
223 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
224 napi_generic_failure, "get callback reference failed");
225 CHECK_AND_RETURN_RET_LOG(ref == nullptr, napi_ok, "callback has been registered");
226 napi_status status = napi_create_reference(env, callback, NapiUtils::ARGC_ONE, &ref);
227 if (status != napi_ok) {
228 SLOGE("napi_create_reference failed");
229 return status;
230 }
231 if (asyncCallback_ == nullptr) {
232 asyncCallback_ = std::make_shared<NapiAsyncCallback>(env);
233 if (asyncCallback_ == nullptr) {
234 SLOGE("no memory");
235 return napi_generic_failure;
236 }
237 }
238 callbacks_[event].push_back(ref);
239 return napi_ok;
240 }
241
RemoveCallback(napi_env env,int32_t event,napi_value callback)242 napi_status NapiAVCastControllerCallback::RemoveCallback(napi_env env, int32_t event, napi_value callback)
243 {
244 std::lock_guard<std::mutex> lockGuard(lock_);
245 if (callback == nullptr) {
246 SLOGD("Remove callback, the callback is nullptr");
247 for (auto callbackRef = callbacks_[event].begin(); callbackRef != callbacks_[event].end(); ++callbackRef) {
248 napi_status ret = napi_delete_reference(env, *callbackRef);
249 CHECK_AND_RETURN_RET_LOG(ret == napi_ok, ret, "delete callback reference failed");
250 *callbackRef = nullptr;
251 }
252 callbacks_[event].clear();
253 return napi_ok;
254 }
255 napi_ref ref = nullptr;
256 CHECK_AND_RETURN_RET_LOG(napi_ok == NapiUtils::GetRefByCallback(env, callbacks_[event], callback, ref),
257 napi_generic_failure, "get callback reference failed");
258 CHECK_AND_RETURN_RET_LOG(ref != nullptr, napi_ok, "callback has been remove");
259 callbacks_[event].remove(ref);
260 return napi_delete_reference(env, ref);
261 }
262 }
263