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 "audio_haptic_player_impl.h"
17 #include "audio_haptic_sound_low_latency_impl.h"
18 #include "audio_haptic_sound_normal_impl.h"
19
20 #include "audio_haptic_log.h"
21 #include "media_errors.h"
22
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticPlayerImpl"};
25 }
26
27 namespace OHOS {
28 namespace Media {
29 const int32_t LOAD_WAIT_SECONDS = 2;
30 const int32_t LOAD_WAIT_SECONDS_FOR_LOOP = 40;
31
32 std::mutex AudioHapticPlayerFactory::createPlayerMutex_;
33
CreateAudioHapticPlayer(const AudioHapticPlayerParam & param)34 std::shared_ptr<AudioHapticPlayer> AudioHapticPlayerFactory::CreateAudioHapticPlayer(
35 const AudioHapticPlayerParam ¶m)
36 {
37 std::lock_guard<std::mutex> lock(createPlayerMutex_);
38 // Create audio haptic player using the param.
39 std::shared_ptr<AudioHapticPlayerImpl> audioHapticPlayer = std::make_shared<AudioHapticPlayerImpl>();
40 audioHapticPlayer->SetPlayerParam(param);
41 audioHapticPlayer->LoadPlayer();
42 return audioHapticPlayer;
43 }
44
45 std::mutex AudioHapticSound::createAudioHapticSoundMutex_;
46
CreateAudioHapticSound(const AudioLatencyMode & latencyMode,const std::string & audioUri,const bool & muteAudio,const AudioStandard::StreamUsage & streamUsage,const bool & parallelPlayFlag)47 std::shared_ptr<AudioHapticSound> AudioHapticSound::CreateAudioHapticSound(
48 const AudioLatencyMode &latencyMode, const std::string &audioUri, const bool &muteAudio,
49 const AudioStandard::StreamUsage &streamUsage, const bool ¶llelPlayFlag)
50 {
51 if (latencyMode != AUDIO_LATENCY_MODE_NORMAL && latencyMode != AUDIO_LATENCY_MODE_FAST) {
52 MEDIA_LOGE("Invalid param: the latency mode %{public}d is unsupported.", latencyMode);
53 return nullptr;
54 }
55
56 std::lock_guard<std::mutex> lock(createAudioHapticSoundMutex_);
57 std::shared_ptr<AudioHapticSound> audioHapticSound = nullptr;
58 switch (latencyMode) {
59 case AUDIO_LATENCY_MODE_NORMAL:
60 audioHapticSound = std::make_shared<AudioHapticSoundNormalImpl>(audioUri, muteAudio, streamUsage);
61 break;
62 case AUDIO_LATENCY_MODE_FAST:
63 audioHapticSound = std::make_shared<AudioHapticSoundLowLatencyImpl>(
64 audioUri, muteAudio, streamUsage, parallelPlayFlag);
65 break;
66 default:
67 MEDIA_LOGE("Invalid param: the latency mode %{public}d is unsupported.", latencyMode);
68 break;
69 }
70 return audioHapticSound;
71 }
72
AudioHapticPlayerImpl()73 AudioHapticPlayerImpl::AudioHapticPlayerImpl()
74 : latencyMode_(AUDIO_LATENCY_MODE_NORMAL),
75 muteAudio_(false),
76 muteHaptic_(false),
77 audioUri_("")
78 {
79 }
80
~AudioHapticPlayerImpl()81 AudioHapticPlayerImpl::~AudioHapticPlayerImpl()
82 {
83 if (playerState_ != AudioHapticPlayerState::STATE_RELEASED) {
84 ReleaseVibrator();
85 ReleaseSound();
86 }
87 }
88
SetPlayerParam(const AudioHapticPlayerParam & param)89 void AudioHapticPlayerImpl::SetPlayerParam(const AudioHapticPlayerParam ¶m)
90 {
91 muteAudio_ = param.options.muteAudio;
92 muteHaptic_ = param.options.muteHaptics;
93 parallelPlayFlag_ = param.options.parallelPlayFlag;
94 audioUri_ = param.audioUri;
95 hapticSource_ = param.hapticSource;
96 latencyMode_ = param.latencyMode;
97 streamUsage_ = param.streamUsage;
98 }
99
LoadPlayer()100 void AudioHapticPlayerImpl::LoadPlayer()
101 {
102 // Load audio player
103 audioHapticSound_ = AudioHapticSound::CreateAudioHapticSound(
104 latencyMode_, audioUri_, muteAudio_, streamUsage_, parallelPlayFlag_);
105 CHECK_AND_RETURN_LOG(audioHapticSound_ != nullptr, "Failed to create audio haptic sound instance");
106 soundCallback_ = std::make_shared<AudioHapticSoundCallbackImpl>(shared_from_this());
107 (void)audioHapticSound_->SetAudioHapticSoundCallback(soundCallback_);
108
109 // Load vibrator
110 audioHapticVibrator_ = AudioHapticVibrator::CreateAudioHapticVibrator(*this);
111 CHECK_AND_RETURN_LOG(audioHapticVibrator_ != nullptr, "Failed to create audio haptic vibrator instance");
112 }
113
IsMuted(const AudioHapticType & audioHapticType) const114 bool AudioHapticPlayerImpl::IsMuted(const AudioHapticType &audioHapticType) const
115 {
116 if (audioHapticType == AUDIO_HAPTIC_TYPE_AUDIO) {
117 return muteAudio_;
118 } else if (audioHapticType == AUDIO_HAPTIC_TYPE_HAPTIC) {
119 return muteHaptic_;
120 }
121 MEDIA_LOGE("IsMuted: invalid audioHapticType %{public}d", audioHapticType);
122 return false;
123 }
124
Prepare()125 int32_t AudioHapticPlayerImpl::Prepare()
126 {
127 int32_t result = MSERR_OK;
128 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
129 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
130 "Audio haptic sound is nullptr");
131 CHECK_AND_RETURN_RET_LOG(audioUri_ != "", MSERR_OPEN_FILE_FAILED, "Invalid val: audio uri is empty");
132 result = audioHapticSound_->PrepareSound();
133 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to load audio file");
134
135 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
136 "Audio haptic vibrator is nullptr");
137 result = audioHapticVibrator_->PreLoad(hapticSource_, streamUsage_);
138 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to load vobration file");
139
140 playerState_ = AudioHapticPlayerState::STATE_PREPARED;
141 return MSERR_OK;
142 }
143
Start()144 int32_t AudioHapticPlayerImpl::Start()
145 {
146 int32_t result = MSERR_OK;
147 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
148
149 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
150 "Audio haptic vibrator is nullptr");
151
152 if (vibrateThread_ != nullptr && vibrateThread_->joinable()) {
153 vibrateThread_->join();
154 vibrateThread_.reset();
155 }
156 if (vibrateThread_ == nullptr) {
157 ResetVibrateState();
158 vibrateThread_ = std::make_shared<std::thread>([this] { StartVibrate(); });
159 }
160
161 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
162 "Audio haptic sound is nullptr");
163 result = audioHapticSound_->StartSound();
164 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to start sound.");
165
166 playerState_ = AudioHapticPlayerState::STATE_RUNNING;
167 return result;
168 }
169
Stop()170 int32_t AudioHapticPlayerImpl::Stop()
171 {
172 int32_t result = MSERR_OK;
173 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
174
175 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
176 "Audio haptic vibrator is nullptr");
177 StopVibrate();
178
179 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
180 "Audio haptic sound is nullptr");
181 result = audioHapticSound_->StopSound();
182 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to stop sound.");
183
184 playerState_ = AudioHapticPlayerState::STATE_STOPPED;
185 return result;
186 }
187
Release()188 int32_t AudioHapticPlayerImpl::Release()
189 {
190 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
191 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, MSERR_OK,
192 "The audio haptic player has been released.");
193
194 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
195 "Audio haptic vibrator is nullptr");
196 ReleaseVibrator();
197
198 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
199 "Audio haptic sound is nullptr");
200 ReleaseSound();
201
202 playerState_ = AudioHapticPlayerState::STATE_RELEASED;
203 return MSERR_OK;
204 }
205
ReleaseVibrator()206 void AudioHapticPlayerImpl::ReleaseVibrator()
207 {
208 if (audioHapticVibrator_ != nullptr) {
209 audioHapticVibrator_->StopVibrate();
210 }
211 {
212 // When player is releasing,notify vibrate thread immediately
213 std::lock_guard<std::mutex> lockVibrate(waitStartVibrateMutex_);
214 isAudioPlayFirstFrame_ = true;
215 isVibrationStopped_ = true;
216 condStartVibrate_.notify_one();
217 }
218 if (vibrateThread_ != nullptr && vibrateThread_->joinable()) {
219 vibrateThread_->join();
220 }
221 vibrateThread_.reset();
222 if (audioHapticVibrator_ != nullptr) {
223 (void)audioHapticVibrator_->Release();
224 audioHapticVibrator_ = nullptr;
225 }
226 }
227
ReleaseSound()228 void AudioHapticPlayerImpl::ReleaseSound()
229 {
230 if (audioHapticSound_ != nullptr) {
231 (void)audioHapticSound_->ReleaseSound();
232 audioHapticSound_ = nullptr;
233 }
234 soundCallback_ = nullptr;
235 }
236
SetVolume(float volume)237 int32_t AudioHapticPlayerImpl::SetVolume(float volume)
238 {
239 MEDIA_LOGI("AudioHapticPlayerImpl::SetVolume %{public}f", volume);
240 if (volume < 0.0f || volume > 1.0f) {
241 MEDIA_LOGE("SetVolume: the volume value is invalid.");
242 return MSERR_INVALID_VAL;
243 }
244
245 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
246 int32_t result = MSERR_OK;
247 volume_ = volume;
248 if (audioHapticSound_ == nullptr) {
249 MEDIA_LOGW("Audio haptic sound is nullptr!");
250 return result;
251 }
252 float actualVolume = volume_ * (muteAudio_ ? 0 : 1);
253 result = audioHapticSound_->SetVolume(actualVolume);
254
255 if (latencyMode_ == AUDIO_LATENCY_MODE_NORMAL &&
256 (streamUsage_ == AudioStandard::StreamUsage::STREAM_USAGE_VOICE_RINGTONE ||
257 streamUsage_ == AudioStandard::StreamUsage::STREAM_USAGE_RINGTONE) &&
258 playerState_ == AudioHapticPlayerState::STATE_RUNNING &&
259 std::abs(volume_ - 0.0f) <= std::numeric_limits<float>::epsilon()) {
260 // only for the call manager ringtone
261 StopVibrate();
262 }
263
264 return result;
265 }
266
SetHapticIntensity(float intensity)267 int32_t AudioHapticPlayerImpl::SetHapticIntensity(float intensity)
268 {
269 MEDIA_LOGI("AudioHapticPlayerImpl::SetHapticIntensity %{public}f", intensity);
270 if (intensity < 1.0f || intensity > 100.0f) {
271 MEDIA_LOGE("SetHapticIntensity: the intensity value is invalid.");
272 return MSERR_INVALID_VAL;
273 }
274
275 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
276 return audioHapticVibrator_->SetHapticIntensity(intensity);
277 }
278
SetLoop(bool loop)279 int32_t AudioHapticPlayerImpl::SetLoop(bool loop)
280 {
281 MEDIA_LOGI("AudioHapticPlayerImpl::SetLoop %{public}d", loop);
282 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
283 int32_t result = MSERR_OK;
284 loop_ = loop;
285 if (audioHapticSound_ == nullptr) {
286 MEDIA_LOGW("Audio haptic sound is nullptr!");
287 return result;
288 }
289 result = audioHapticSound_->SetLoop(loop);
290 return result;
291 }
292
GetHapticsMode() const293 HapticsMode AudioHapticPlayerImpl::GetHapticsMode() const
294 {
295 return hapticsMode_;
296 }
297
SetHapticsMode(HapticsMode hapticsMode)298 void AudioHapticPlayerImpl::SetHapticsMode(HapticsMode hapticsMode)
299 {
300 MEDIA_LOGI("AudioHapticPlayerImpl::SetHapticsMode %{public}d", hapticsMode);
301 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
302 hapticsMode_ = hapticsMode;
303 }
304
SetAudioHapticPlayerCallback(const std::shared_ptr<AudioHapticPlayerCallback> & playerCallback)305 int32_t AudioHapticPlayerImpl::SetAudioHapticPlayerCallback(
306 const std::shared_ptr<AudioHapticPlayerCallback> &playerCallback)
307 {
308 if (playerCallback == nullptr) {
309 MEDIA_LOGE("The audio haptic player callback is nullptr.");
310 return MSERR_INVALID_VAL;
311 }
312
313 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
314 audioHapticPlayerCallback_ = playerCallback;
315 return MSERR_OK;
316 }
317
GetAudioCurrentTime()318 int32_t AudioHapticPlayerImpl::GetAudioCurrentTime()
319 {
320 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, -1, "Audio haptic sound is nullptr");
321 return audioHapticSound_->GetAudioCurrentTime();
322 }
323
StartVibrate()324 int32_t AudioHapticPlayerImpl::StartVibrate()
325 {
326 if (muteHaptic_) {
327 MEDIA_LOGI("StartVibrate: muteHaptic is true. No need to vibrate");
328 return MSERR_OK;
329 }
330
331 MEDIA_LOGI("Enter StartVibrate()");
332 std::unique_lock<std::mutex> lockWait(waitStartVibrateMutex_);
333 do {
334 int32_t waitTime = loop_ ? LOAD_WAIT_SECONDS_FOR_LOOP : LOAD_WAIT_SECONDS;
335 bool waitResult = condStartVibrate_.wait_for(lockWait, std::chrono::seconds(waitTime),
336 [this]() { return isAudioPlayFirstFrame_ || isVibrationStopped_; });
337 if (!waitResult) {
338 MEDIA_LOGE("StartVibrate: Failed to start vibrate (time out).");
339 return MSERR_INVALID_OPERATION;
340 }
341 if (isVibrationStopped_) {
342 MEDIA_LOGI("StartVibrate: audio haptic player has been stopped.");
343 return MSERR_OK;
344 }
345
346 isAudioPlayFirstFrame_ = false; // reset for next time.
347
348 int32_t hapticDelay = audioHapticVibrator_->GetDelayTime();
349 int32_t delay = (static_cast<int32_t>(this->audioLatency_) - hapticDelay) > 0 ?
350 static_cast<int32_t>(this->audioLatency_) - hapticDelay : 0;
351 waitResult = condStartVibrate_.wait_for(lockWait, std::chrono::milliseconds(delay),
352 [this]() { return isVibrationStopped_; });
353 if (isVibrationStopped_) {
354 MEDIA_LOGI("StartVibrate: audio haptic player has been stopped.");
355 return MSERR_OK;
356 }
357 MEDIA_LOGI("The first frame of audio is about to start. Triggering the vibration.");
358 audioHapticVibrator_->StartVibrate(latencyMode_);
359 } while (loop_ && !isVibrationStopped_);
360
361 return MSERR_OK;
362 }
363
StopVibrate()364 void AudioHapticPlayerImpl::StopVibrate()
365 {
366 MEDIA_LOGI("Stop vibrate for audio haptic player right now.");
367 if (audioHapticVibrator_ != nullptr) {
368 audioHapticVibrator_->StopVibrate();
369 } else {
370 MEDIA_LOGW("The audio haptic vibrator is nullptr!");
371 }
372 {
373 std::lock_guard<std::mutex> lockVibrate(waitStartVibrateMutex_);
374 isVibrationStopped_ = true;
375 condStartVibrate_.notify_one();
376 }
377 if (vibrateThread_ != nullptr && vibrateThread_->joinable()) {
378 vibrateThread_->join();
379 }
380 vibrateThread_.reset();
381 }
382
ResetVibrateState()383 void AudioHapticPlayerImpl::ResetVibrateState()
384 {
385 isVibrationStopped_ = false;
386 if (audioHapticVibrator_ != nullptr) {
387 audioHapticVibrator_->ResetStopState();
388 } else {
389 MEDIA_LOGW("The audio haptic vibrator is nullptr!");
390 }
391 }
392
NotifyInterruptEvent(const AudioStandard::InterruptEvent & interruptEvent)393 void AudioHapticPlayerImpl::NotifyInterruptEvent(const AudioStandard::InterruptEvent &interruptEvent)
394 {
395 std::shared_ptr<AudioHapticPlayerCallback> cb = audioHapticPlayerCallback_.lock();
396 if (cb != nullptr) {
397 MEDIA_LOGI("NotifyInterruptEvent for napi object or caller");
398 cb->OnInterrupt(interruptEvent);
399 } else {
400 MEDIA_LOGE("NotifyInterruptEvent: audioHapticPlayerCallback_ is nullptr");
401 }
402 }
403
NotifyEndOfStreamEvent()404 void AudioHapticPlayerImpl::NotifyEndOfStreamEvent()
405 {
406 MEDIA_LOGI("NotifyEndOfStreamEvent");
407 std::thread (HandleEndOfStreamEventThreadFunc, shared_from_this()).detach();
408 std::shared_ptr<AudioHapticPlayerCallback> cb = audioHapticPlayerCallback_.lock();
409 if (cb != nullptr) {
410 MEDIA_LOGI("NotifyEndOfStreamEvent for napi object or caller");
411 cb->OnEndOfStream();
412 } else {
413 MEDIA_LOGE("NotifyEndOfStreamEvent: audioHapticPlayerCallback_ is nullptr");
414 }
415 }
416
HandleEndOfStreamEventThreadFunc(std::weak_ptr<AudioHapticPlayerImpl> player)417 void AudioHapticPlayerImpl::HandleEndOfStreamEventThreadFunc(std::weak_ptr<AudioHapticPlayerImpl> player)
418 {
419 std::shared_ptr<AudioHapticPlayerImpl> playerPtr = player.lock();
420 if (playerPtr != nullptr) {
421 playerPtr->HandleEndOfStreamEvent();
422 }
423 }
424
HandleEndOfStreamEvent()425 void AudioHapticPlayerImpl::HandleEndOfStreamEvent()
426 {
427 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
428 if (playerState_ == AudioHapticPlayerState::STATE_RELEASED) {
429 MEDIA_LOGE("The audio haptic player has been released!");
430 return;
431 }
432 StopVibrate();
433 playerState_ = AudioHapticPlayerState::STATE_STOPPED;
434 }
435
NotifyErrorEvent(int32_t errCode)436 void AudioHapticPlayerImpl::NotifyErrorEvent(int32_t errCode)
437 {
438 std::shared_ptr<AudioHapticPlayerCallback> cb = audioHapticPlayerCallback_.lock();
439 if (cb != nullptr) {
440 MEDIA_LOGI("NotifyErrorEvent for napi object or caller. errCode: %{public}d", errCode);
441 cb->OnError(errCode);
442 } else {
443 MEDIA_LOGE("NotifyErrorEvent: audioHapticPlayerCallback_ is nullptr");
444 }
445 }
446
NotifyStartVibrate(const uint64_t & latency)447 void AudioHapticPlayerImpl::NotifyStartVibrate(const uint64_t &latency)
448 {
449 std::lock_guard<std::mutex> lock(this->waitStartVibrateMutex_);
450 this->isAudioPlayFirstFrame_ = true;
451 this->audioLatency_ = latency;
452 this->condStartVibrate_.notify_one();
453 }
454
455 // Callback class symbols
AudioHapticSoundCallbackImpl(std::shared_ptr<AudioHapticPlayerImpl> audioHapticPlayerImpl)456 AudioHapticSoundCallbackImpl::AudioHapticSoundCallbackImpl(std::shared_ptr<AudioHapticPlayerImpl> audioHapticPlayerImpl)
457 : audioHapticPlayerImpl_(audioHapticPlayerImpl) {}
458
OnEndOfStream()459 void AudioHapticSoundCallbackImpl::OnEndOfStream()
460 {
461 MEDIA_LOGI("OnEndOfStream reported from audio haptic sound.");
462 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
463 if (player == nullptr) {
464 MEDIA_LOGE("The audio haptic player has been released.");
465 return;
466 }
467 player->NotifyEndOfStreamEvent();
468 }
469
OnError(int32_t errorCode)470 void AudioHapticSoundCallbackImpl::OnError(int32_t errorCode)
471 {
472 MEDIA_LOGE("OnError reported from audio haptic sound: %{public}d", errorCode);
473 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
474 if (player == nullptr) {
475 MEDIA_LOGE("The audio haptic player has been released.");
476 return;
477 }
478 player->NotifyErrorEvent(errorCode);
479 }
480
OnInterrupt(const AudioStandard::InterruptEvent & interruptEvent)481 void AudioHapticSoundCallbackImpl::OnInterrupt(const AudioStandard::InterruptEvent &interruptEvent)
482 {
483 MEDIA_LOGI("OnInterrupt from audio haptic sound. hintType: %{public}d", interruptEvent.hintType);
484 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
485 if (player == nullptr) {
486 MEDIA_LOGE("The audio haptic player has been released.");
487 return;
488 }
489 player->NotifyInterruptEvent(interruptEvent);
490 }
491
OnFirstFrameWriting(uint64_t latency)492 void AudioHapticSoundCallbackImpl::OnFirstFrameWriting(uint64_t latency)
493 {
494 MEDIA_LOGI("OnFirstFrameWriting from audio haptic sound. Latency %{public}" PRIu64 "", latency);
495 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
496 if (player == nullptr) {
497 MEDIA_LOGE("The audio haptic player has been released.");
498 return;
499 }
500 player->NotifyStartVibrate(latency);
501 }
502 } // namesapce AudioStandard
503 } // namespace OHOS
504