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
18 #include <cstdint>
19 #include <chrono>
20 #include <unistd.h>
21 #include <random>
22
23 #include "parameter.h"
24
25 #include "audio_haptic_sound_low_latency_impl.h"
26 #include "audio_haptic_sound_normal_impl.h"
27
28 #include "audio_haptic_log.h"
29 #include "media_errors.h"
30 #include "media_monitor_manager.h"
31
32 namespace {
33 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticPlayerImpl"};
34 }
35
36 namespace OHOS {
37 namespace Media {
38 const int32_t LOAD_WAIT_SECONDS = 2;
39 const int32_t LOAD_WAIT_SECONDS_FOR_LOOP = 40;
40 const int32_t NORMAL_LOOP_FIRST_WAIT_MS = 80;
41 const int32_t NORMAL_LOOP_FOLLOW_WAIT_MS = 40;
42
GenerateSyncId()43 static int32_t GenerateSyncId()
44 {
45 static constexpr uint8_t pidBits = 8; // Number of bits allocated for the Process ID
46 static constexpr uint8_t randomBits = 8; // Number of bits allocated for the random value
47 static constexpr uint8_t timeBits = 24; // Number of bits allocated for the time difference
48
49 static constexpr uint32_t pidMask = (1 << pidBits) - 1; // Mask for PID (0xFF for 8 bits)
50 static constexpr uint32_t randomMask = (1 << randomBits) - 1; // Mask for random value (0xFF for 8 bits)
51 static constexpr uint32_t timeMask = (1 << timeBits) - 1; // Mask for time difference (0xFFFFFF for 24 bits)
52
53 static thread_local pid_t pid = getpid();
54 static thread_local auto startTime = std::chrono::steady_clock::now();
55 static thread_local std::mt19937 gen(std::random_device{}());
56 // Use constants to define the distribution range
57 static thread_local std::uniform_int_distribution<uint16_t> dist(0, randomMask);
58
59 auto now = std::chrono::steady_clock::now();
60 auto duration = now - startTime;
61 auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
62
63 uint32_t pidUnsigned = static_cast<uint32_t>(pid);
64 uint64_t microsUnsigned = static_cast<uint64_t>(micros);
65
66 return
67 ((microsUnsigned & timeMask) << (pidBits + randomBits)) | // Shift time part by 16 bits (8+8)
68 ((pidUnsigned & pidMask) << randomBits) | // Shift PID part by 8 bits
69 (dist(gen) & randomMask); // Random value occupies the lowest 8 bits
70 }
71
IsSupportDSP(void)72 static bool IsSupportDSP(void)
73 {
74 constexpr const char* supportDspKey = "const.multimedia.audio.support_hadware_audio_haptic_sync";
75 constexpr const uint32_t paramTrueLen = 4; // "true" 4bytes
76 constexpr const uint32_t paramFalseLen = 5; // "false" 5bytes
77 constexpr const char* paramTrue = "true";
78 constexpr const char* paramFalse = "false";
79
80 char result[paramFalseLen + 1] = {0};
81 // Returns the number of bytes of the system parameter if the operation is successful.
82 int len = GetParameter(supportDspKey, paramFalse, result, paramFalseLen + 1);
83 CHECK_AND_RETURN_RET_LOG(len == paramFalseLen || len == paramTrueLen, false, "GetParameter len is invalid.");
84
85 if (strncmp(result, paramTrue, paramTrueLen) == 0) {
86 MEDIA_LOGW("AudioHapticPlayerImpl support DSP!");
87 return true;
88 }
89 MEDIA_LOGW("AudioHapticPlayerImpl doesn't support DSP!");
90 return false;
91 }
92
93 std::mutex AudioHapticPlayerFactory::createPlayerMutex_;
94
CreateAudioHapticPlayer(const AudioHapticPlayerParam & param)95 std::shared_ptr<AudioHapticPlayer> AudioHapticPlayerFactory::CreateAudioHapticPlayer(
96 const AudioHapticPlayerParam ¶m)
97 {
98 std::lock_guard<std::mutex> lock(createPlayerMutex_);
99 // Create audio haptic player using the param.
100 std::shared_ptr<AudioHapticPlayerImpl> audioHapticPlayer = std::make_shared<AudioHapticPlayerImpl>();
101 audioHapticPlayer->SetPlayerParam(param);
102 audioHapticPlayer->LoadPlayer();
103 return audioHapticPlayer;
104 }
105
106 std::mutex AudioHapticSound::createAudioHapticSoundMutex_;
107
CreateAudioHapticSound(const AudioLatencyMode & latencyMode,const AudioSource & audioSource,const bool & muteAudio,const AudioStandard::StreamUsage & streamUsage,const bool & parallelPlayFlag)108 std::shared_ptr<AudioHapticSound> AudioHapticSound::CreateAudioHapticSound(
109 const AudioLatencyMode &latencyMode, const AudioSource& audioSource, const bool &muteAudio,
110 const AudioStandard::StreamUsage &streamUsage, const bool ¶llelPlayFlag)
111 {
112 if (latencyMode != AUDIO_LATENCY_MODE_NORMAL && latencyMode != AUDIO_LATENCY_MODE_FAST) {
113 MEDIA_LOGE("Invalid param: the latency mode %{public}d is unsupported.", latencyMode);
114 return nullptr;
115 }
116
117 std::lock_guard<std::mutex> lock(createAudioHapticSoundMutex_);
118 std::shared_ptr<AudioHapticSound> audioHapticSound = nullptr;
119 switch (latencyMode) {
120 case AUDIO_LATENCY_MODE_NORMAL:
121 audioHapticSound =
122 std::make_shared<AudioHapticSoundNormalImpl>(audioSource, muteAudio, streamUsage);
123 break;
124 case AUDIO_LATENCY_MODE_FAST:
125 audioHapticSound = std::make_shared<AudioHapticSoundLowLatencyImpl>(
126 audioSource, muteAudio, streamUsage, parallelPlayFlag);
127 break;
128 default:
129 MEDIA_LOGE("Invalid param: the latency mode %{public}d is unsupported.", latencyMode);
130 break;
131 }
132 return audioHapticSound;
133 }
134
AudioHapticPlayerImpl()135 AudioHapticPlayerImpl::AudioHapticPlayerImpl()
136 : latencyMode_(AUDIO_LATENCY_MODE_NORMAL),
137 muteAudio_(false),
138 muteHaptic_(false)
139 {
140 isSupportDSPSync_ = IsSupportDSP();
141 }
142
~AudioHapticPlayerImpl()143 AudioHapticPlayerImpl::~AudioHapticPlayerImpl()
144 {
145 if (playerState_ != AudioHapticPlayerState::STATE_RELEASED) {
146 ReleaseVibrator();
147 }
148 }
149
SetPlayerParam(const AudioHapticPlayerParam & param)150 void AudioHapticPlayerImpl::SetPlayerParam(const AudioHapticPlayerParam ¶m)
151 {
152 muteAudio_ = param.options.muteAudio;
153 muteHaptic_ = param.options.muteHaptics;
154 parallelPlayFlag_ = param.options.parallelPlayFlag;
155 audioSource_ = param.audioSource;
156 hapticSource_ = param.hapticSource;
157 latencyMode_ = param.latencyMode;
158 streamUsage_ = param.streamUsage;
159 }
160
LoadPlayer()161 void AudioHapticPlayerImpl::LoadPlayer()
162 {
163 // Load audio player
164 audioHapticSound_ = AudioHapticSound::CreateAudioHapticSound(
165 latencyMode_, audioSource_, muteAudio_, streamUsage_, parallelPlayFlag_);
166 CHECK_AND_RETURN_LOG(audioHapticSound_ != nullptr, "Failed to create audio haptic sound instance");
167 soundCallback_ = std::make_shared<AudioHapticSoundCallbackImpl>(shared_from_this());
168 (void)audioHapticSound_->SetAudioHapticSoundCallback(soundCallback_);
169
170 // Load vibrator
171 audioHapticVibrator_ = AudioHapticVibrator::CreateAudioHapticVibrator(*this);
172 CHECK_AND_RETURN_LOG(audioHapticVibrator_ != nullptr, "Failed to create audio haptic vibrator instance");
173 audioHapticVibrator_->SetAudioHapticSyncId(audioHapticSyncId_);
174 }
175
IsMuted(const AudioHapticType & audioHapticType) const176 bool AudioHapticPlayerImpl::IsMuted(const AudioHapticType &audioHapticType) const
177 {
178 if (audioHapticType == AUDIO_HAPTIC_TYPE_AUDIO) {
179 return muteAudio_;
180 } else if (audioHapticType == AUDIO_HAPTIC_TYPE_HAPTIC) {
181 return muteHaptic_;
182 }
183 MEDIA_LOGE("IsMuted: invalid audioHapticType %{public}d", audioHapticType);
184 return false;
185 }
186
Prepare()187 int32_t AudioHapticPlayerImpl::Prepare()
188 {
189 int32_t result = MSERR_OK;
190 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
191 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
192 "Audio haptic sound is nullptr");
193 CHECK_AND_RETURN_RET_LOG(audioSource_.audioUri != "" || audioSource_.fd > INVALID_FD,
194 MSERR_OPEN_FILE_FAILED, "Invalid val: audioSource");
195 result = audioHapticSound_->PrepareSound();
196 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to load audio file");
197
198 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
199 "Audio haptic vibrator is nullptr");
200 result = audioHapticVibrator_->PreLoad(hapticSource_, streamUsage_);
201 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to load vobration file");
202
203 playerState_ = AudioHapticPlayerState::STATE_PREPARED;
204 return MSERR_OK;
205 }
206
Start()207 int32_t AudioHapticPlayerImpl::Start()
208 {
209 int32_t result = MSERR_OK;
210 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
211
212 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
213 "Audio haptic vibrator is nullptr");
214 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
215 "Audio haptic sound is nullptr");
216 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RUNNING, result,
217 "Audio haptic already running");
218
219 // If DSP synchronization is supported, generate the syncId before starting
220 if (isSupportDSPSync_) {
221 audioHapticSyncId_ = GenerateSyncId();
222 }
223
224 if (vibrateThread_ == nullptr) {
225 ResetVibrateState();
226 vibrateThread_ = std::make_shared<std::thread>([this] { StartVibrate(); });
227 }
228 result = audioHapticSound_->StartSound(audioHapticSyncId_.load());
229 SendHapticPlayerEvent(MSERR_OK, "START_HAPTIC_PLAYER");
230 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to start sound.");
231 MEDIA_LOGW("StartSound() has been executed successfully!");
232 playerState_ = AudioHapticPlayerState::STATE_RUNNING;
233 return result;
234 }
235
Stop()236 int32_t AudioHapticPlayerImpl::Stop()
237 {
238 int32_t result = MSERR_OK;
239 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
240
241 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
242 "Audio haptic vibrator is nullptr");
243 StopVibrate();
244
245 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
246 "Audio haptic sound is nullptr");
247 result = audioHapticSound_->StopSound();
248 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "Failed to stop sound.");
249
250 playerState_ = AudioHapticPlayerState::STATE_STOPPED;
251 return result;
252 }
253
Release()254 int32_t AudioHapticPlayerImpl::Release()
255 {
256 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
257 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, MSERR_OK,
258 "The audio haptic player has been released.");
259
260 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, MSERR_INVALID_OPERATION,
261 "Audio haptic vibrator is nullptr");
262 ReleaseVibrator();
263
264 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, MSERR_INVALID_OPERATION,
265 "Audio haptic sound is nullptr");
266 ReleaseSound();
267
268 playerState_ = AudioHapticPlayerState::STATE_RELEASED;
269 return MSERR_OK;
270 }
271
ReleaseVibrator()272 void AudioHapticPlayerImpl::ReleaseVibrator()
273 {
274 if (audioHapticVibrator_ != nullptr) {
275 audioHapticVibrator_->StopVibrate();
276 }
277 {
278 // When player is releasing,notify vibrate thread immediately
279 std::lock_guard<std::mutex> lockVibrate(waitStartVibrateMutex_);
280 canStartVibrate_ = true;
281 isVibrationStopped_ = true;
282 condStartVibrate_.notify_one();
283 }
284 if (vibrateThread_ != nullptr && vibrateThread_->joinable()) {
285 vibrateThread_->join();
286 }
287 vibrateThread_.reset();
288 if (audioHapticVibrator_ != nullptr) {
289 (void)audioHapticVibrator_->Release();
290 audioHapticVibrator_ = nullptr;
291 }
292 }
293
ReleaseSound()294 void AudioHapticPlayerImpl::ReleaseSound()
295 {
296 if (audioHapticSound_ != nullptr) {
297 (void)audioHapticSound_->ReleaseSound();
298 audioHapticSound_ = nullptr;
299 }
300 soundCallback_ = nullptr;
301 }
302
SetVolume(float volume)303 int32_t AudioHapticPlayerImpl::SetVolume(float volume)
304 {
305 MEDIA_LOGI("AudioHapticPlayerImpl::SetVolume %{public}f", volume);
306 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, ERR_OPERATE_NOT_ALLOWED,
307 "The audio haptic player has been released.");
308 if (volume < 0.0f || volume > 1.0f) {
309 MEDIA_LOGE("SetVolume: the volume value is invalid.");
310 return MSERR_INVALID_VAL;
311 }
312
313 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
314 int32_t result = MSERR_OK;
315 volume_ = volume;
316 if (audioHapticSound_ == nullptr) {
317 MEDIA_LOGW("Audio haptic sound is nullptr!");
318 return result;
319 }
320 float actualVolume = volume_ * (muteAudio_ ? 0 : 1);
321 result = audioHapticSound_->SetVolume(actualVolume);
322
323 if (latencyMode_ == AUDIO_LATENCY_MODE_NORMAL &&
324 (streamUsage_ == AudioStandard::StreamUsage::STREAM_USAGE_VOICE_RINGTONE ||
325 streamUsage_ == AudioStandard::StreamUsage::STREAM_USAGE_RINGTONE) &&
326 playerState_ == AudioHapticPlayerState::STATE_RUNNING &&
327 std::abs(volume_ - 0.0f) <= std::numeric_limits<float>::epsilon()) {
328 // only for the call manager ringtone
329 StopVibrate();
330 }
331
332 return result;
333 }
334
IsHapticsRampSupported()335 bool AudioHapticPlayerImpl::IsHapticsRampSupported()
336 {
337 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
338 if (audioHapticVibrator_ != nullptr) {
339 return audioHapticVibrator_->IsHapticsCustomSupported();
340 }
341 return false;
342 }
343
IsHapticsIntensityAdjustmentSupported()344 bool AudioHapticPlayerImpl::IsHapticsIntensityAdjustmentSupported()
345 {
346 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
347 if (audioHapticVibrator_ != nullptr) {
348 return audioHapticVibrator_->IsHapticsCustomSupported();
349 }
350 return false;
351 }
352
EnableHapticsInSilentMode(bool enable)353 int32_t AudioHapticPlayerImpl::EnableHapticsInSilentMode(bool enable)
354 {
355 int32_t result = MSERR_OK;
356 MEDIA_LOGI("AudioHapticPlayerImpl::EnableHapticsInSilentMode %{public}d", enable);
357 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
358
359 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, ERR_OPERATE_NOT_ALLOWED,
360 "The audio haptic player has been released.");
361 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RUNNING, ERR_OPERATE_NOT_ALLOWED,
362 "The audio haptic player is running.");
363
364 if (audioHapticVibrator_ == nullptr) {
365 return ERR_OPERATE_NOT_ALLOWED;
366 }
367
368 audioHapticVibrator_->EnableHapticsInSilentMode(enable);
369 return result;
370 }
371
SetHapticIntensity(float intensity)372 int32_t AudioHapticPlayerImpl::SetHapticIntensity(float intensity)
373 {
374 MEDIA_LOGI("AudioHapticPlayerImpl::SetHapticIntensity %{public}f", intensity);
375
376 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
377 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, ERR_OPERATE_NOT_ALLOWED,
378 "The audio haptic player has been released.");
379 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr && audioHapticVibrator_->IsHapticsCustomSupported(),
380 NOT_SUPPORTED_CODE, "Function is not supported in current device");
381
382 if (intensity < 1.0f || intensity > 100.0f) {
383 MEDIA_LOGE("SetHapticIntensity: the intensity value is invalid.");
384 return MSERR_INVALID_VAL;
385 }
386
387 return audioHapticVibrator_->SetHapticIntensity(intensity);
388 }
389
SetHapticsFeature(const HapticsFeature & feature)390 int32_t AudioHapticPlayerImpl::SetHapticsFeature(const HapticsFeature &feature)
391 {
392 MEDIA_LOGI("AudioHapticPlayerImpl::SetHapticsFeature %{public}d", feature);
393
394 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
395 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, ERR_OPERATE_NOT_ALLOWED,
396 "The audio haptic player has been released.");
397 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr, ERR_OPERATE_NOT_ALLOWED, "audioHapticVibrator_ is null");
398 CHECK_AND_RETURN_RET_LOG(!isGentle_.load(), ERR_OPERATE_NOT_ALLOWED, "already gentle");
399
400 int32_t result = audioHapticVibrator_->SetHapticsFeature(feature);
401 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "SetHapticsFeature error");
402 isGentle_.store(true);
403
404 return result;
405 }
406
SetHapticsRamp(int32_t duration,float startIntensity,float endIntensity)407 int32_t AudioHapticPlayerImpl::SetHapticsRamp(int32_t duration, float startIntensity, float endIntensity)
408 {
409 MEDIA_LOGI("AudioHapticPlayerImpl::SetHapticsRamp %{public}d, %{public}f, %{public}f",
410 duration, startIntensity, endIntensity);
411
412 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
413 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, ERR_OPERATE_NOT_ALLOWED,
414 "The audio haptic player has been released.");
415 CHECK_AND_RETURN_RET_LOG(!isRamp_.load(), ERR_OPERATE_NOT_ALLOWED, "already ramp");
416 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RUNNING, ERR_OPERATE_NOT_ALLOWED,
417 "can't set when playing haptics");
418 CHECK_AND_RETURN_RET_LOG(audioHapticVibrator_ != nullptr && audioHapticVibrator_->IsHapticsCustomSupported(),
419 NOT_SUPPORTED_CODE, "Function is not supported in current device");
420
421 // duration not less than 100ms
422 if (duration < 100) {
423 MEDIA_LOGE("AudioHapticPlayerImpl::SetHapticsRamp: the duration value is invalid.");
424 return MSERR_INVALID_VAL;
425 }
426
427 if (startIntensity < 1.0f || startIntensity > 100.0f) {
428 MEDIA_LOGE("AudioHapticPlayerImpl::SetHapticsRamp: the startIntensity value is invalid.");
429 return MSERR_INVALID_VAL;
430 }
431
432 if (endIntensity < 1.0f || endIntensity > 100.0f) {
433 MEDIA_LOGE("AudioHapticPlayerImpl::SetHapticsRamp: the endIntensity value is invalid.");
434 return MSERR_INVALID_VAL;
435 }
436
437 int32_t result = audioHapticVibrator_->SetHapticsRamp(duration, startIntensity, endIntensity);
438 CHECK_AND_RETURN_RET_LOG(result == MSERR_OK, result, "SetHapticsRamp error");
439 isRamp_.store(true);
440
441 return result;
442 }
443
SetLoop(bool loop)444 int32_t AudioHapticPlayerImpl::SetLoop(bool loop)
445 {
446 MEDIA_LOGI("AudioHapticPlayerImpl::SetLoop %{public}d", loop);
447 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
448 CHECK_AND_RETURN_RET_LOG(playerState_ != AudioHapticPlayerState::STATE_RELEASED, ERR_OPERATE_NOT_ALLOWED,
449 "The audio haptic player has been released.");
450 int32_t result = MSERR_OK;
451 loop_.store(loop);
452 if (audioHapticSound_ == nullptr) {
453 MEDIA_LOGW("Audio haptic sound is nullptr!");
454 return result;
455 }
456 result = audioHapticSound_->SetLoop(loop);
457 return result;
458 }
459
GetHapticsMode() const460 HapticsMode AudioHapticPlayerImpl::GetHapticsMode() const
461 {
462 return hapticsMode_;
463 }
464
SetHapticsMode(HapticsMode hapticsMode)465 void AudioHapticPlayerImpl::SetHapticsMode(HapticsMode hapticsMode)
466 {
467 MEDIA_LOGI("AudioHapticPlayerImpl::SetHapticsMode %{public}d", hapticsMode);
468 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
469 hapticsMode_ = hapticsMode;
470 }
471
SetAudioHapticPlayerCallback(const std::shared_ptr<AudioHapticPlayerCallback> & playerCallback)472 int32_t AudioHapticPlayerImpl::SetAudioHapticPlayerCallback(
473 const std::shared_ptr<AudioHapticPlayerCallback> &playerCallback)
474 {
475 if (playerCallback == nullptr) {
476 MEDIA_LOGE("The audio haptic player callback is nullptr.");
477 return MSERR_INVALID_VAL;
478 }
479
480 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
481 audioHapticPlayerCallback_ = playerCallback;
482 return MSERR_OK;
483 }
484
GetAudioCurrentTime()485 int32_t AudioHapticPlayerImpl::GetAudioCurrentTime()
486 {
487 CHECK_AND_RETURN_RET_LOG(audioHapticSound_ != nullptr, -1, "Audio haptic sound is nullptr");
488 return audioHapticSound_->GetAudioCurrentTime();
489 }
490
GetDelayTime(int32_t playedTimes)491 int32_t AudioHapticPlayerImpl::GetDelayTime(int32_t playedTimes)
492 {
493 // normal mode needs to calc waiting time, fast mode start vib immediatelly
494 if (latencyMode_ == AUDIO_LATENCY_MODE_NORMAL) {
495 return playedTimes > 0 ? NORMAL_LOOP_FOLLOW_WAIT_MS : NORMAL_LOOP_FIRST_WAIT_MS;
496 }
497
498 return 0;
499 }
500
StartVibrate()501 int32_t AudioHapticPlayerImpl::StartVibrate()
502 {
503 if (muteHaptic_) {
504 MEDIA_LOGI("StartVibrate: muteHaptic is true. No need to vibrate");
505 SendHapticPlayerEvent(MSERR_OK, "NO_NEED_VIBRATE");
506 return MSERR_OK;
507 }
508
509 MEDIA_LOGI("Enter StartVibrate()");
510 std::unique_lock<std::mutex> lockWait(waitStartVibrateMutex_);
511 int32_t playedTimes = 0;
512 do {
513 int32_t waitTime = loop_.load() ? LOAD_WAIT_SECONDS_FOR_LOOP : LOAD_WAIT_SECONDS;
514 bool waitResult = condStartVibrate_.wait_for(lockWait, std::chrono::seconds(waitTime),
515 [this]() { return canStartVibrate_ || isVibrationStopped_; });
516 if (!waitResult) {
517 MEDIA_LOGE("StartVibrate: Failed to start vibrate (time out).");
518 SendHapticPlayerEvent(MSERR_INVALID_OPERATION, "VIBRATE_TIME_OUT");
519 return MSERR_INVALID_OPERATION;
520 }
521 if (isVibrationStopped_) {
522 MEDIA_LOGI("StartVibrate: audio haptic player has been stopped.");
523 SendHapticPlayerEvent(MSERR_OK, "HAPTIC_PLAYER_STOP");
524 return MSERR_OK;
525 }
526
527 canStartVibrate_ = false; // reset for next time.
528 int32_t delayMS = GetDelayTime(playedTimes); // audio haptics sync offset
529 // If new synchronization is unsupported, use old solution
530 if (!isSupportDSPSync_) {
531 int32_t hapticDelay = audioHapticVibrator_->GetDelayTime();
532 delayMS = (static_cast<int32_t>(this->audioLatency_) - hapticDelay) > 0 ?
533 static_cast<int32_t>(this->audioLatency_) - hapticDelay : 0;
534 }
535 waitResult = condStartVibrate_.wait_for(lockWait, std::chrono::milliseconds(delayMS),
536 [this]() { return isVibrationStopped_.load(); });
537 if (isVibrationStopped_) {
538 MEDIA_LOGI("StartVibrate: audio haptic player has been stopped.");
539 SendHapticPlayerEvent(MSERR_OK, "HAPTIC_PLAYER_STOP");
540 return MSERR_OK;
541 }
542 MEDIA_LOGI("The first frame of audio is about to start. Triggering the vibration.");
543 isVibrationRunning_.store(true);
544 audioHapticVibrator_->SetAudioHapticSyncId(audioHapticSyncId_.load());
545 audioHapticVibrator_->StartVibrate(latencyMode_);
546 isVibrationRunning_.store(false);
547 playedTimes++;
548 } while (loop_.load() && !isVibrationStopped_);
549
550 SendHapticPlayerEvent(MSERR_OK, "START_VIBRATE");
551 return MSERR_OK;
552 }
553
StopVibrate()554 void AudioHapticPlayerImpl::StopVibrate()
555 {
556 MEDIA_LOGI("Stop vibrate for audio haptic player right now.");
557 if (audioHapticVibrator_ != nullptr) {
558 audioHapticVibrator_->StopVibrate();
559 } else {
560 MEDIA_LOGW("The audio haptic vibrator is nullptr!");
561 }
562 {
563 std::lock_guard<std::mutex> lockVibrate(waitStartVibrateMutex_);
564 isVibrationStopped_ = true;
565 condStartVibrate_.notify_one();
566 }
567 if (vibrateThread_ != nullptr && vibrateThread_->joinable()) {
568 vibrateThread_->join();
569 }
570 vibrateThread_.reset();
571 }
572
ResetVibrateState()573 void AudioHapticPlayerImpl::ResetVibrateState()
574 {
575 isVibrationStopped_ = false;
576 if (audioHapticVibrator_ != nullptr) {
577 audioHapticVibrator_->ResetStopState();
578 } else {
579 MEDIA_LOGW("The audio haptic vibrator is nullptr!");
580 }
581 }
582
NotifyInterruptEvent(const AudioStandard::InterruptEvent & interruptEvent)583 void AudioHapticPlayerImpl::NotifyInterruptEvent(const AudioStandard::InterruptEvent &interruptEvent)
584 {
585 std::shared_ptr<AudioHapticPlayerCallback> cb = audioHapticPlayerCallback_.lock();
586 if (cb != nullptr) {
587 MEDIA_LOGI("NotifyInterruptEvent for napi object or caller");
588 cb->OnInterrupt(interruptEvent);
589 } else {
590 MEDIA_LOGE("NotifyInterruptEvent: audioHapticPlayerCallback_ is nullptr");
591 }
592 }
593
NotifyEndOfStreamEvent()594 void AudioHapticPlayerImpl::NotifyEndOfStreamEvent()
595 {
596 MEDIA_LOGI("NotifyEndOfStreamEvent");
597 std::thread (HandleEndOfStreamEventThreadFunc, shared_from_this()).detach();
598 std::shared_ptr<AudioHapticPlayerCallback> cb = audioHapticPlayerCallback_.lock();
599 if (cb != nullptr) {
600 MEDIA_LOGI("NotifyEndOfStreamEvent for napi object or caller");
601 cb->OnEndOfStream();
602 } else {
603 MEDIA_LOGE("NotifyEndOfStreamEvent: audioHapticPlayerCallback_ is nullptr");
604 }
605 }
606
HandleEndOfStreamEventThreadFunc(std::weak_ptr<AudioHapticPlayerImpl> player)607 void AudioHapticPlayerImpl::HandleEndOfStreamEventThreadFunc(std::weak_ptr<AudioHapticPlayerImpl> player)
608 {
609 std::shared_ptr<AudioHapticPlayerImpl> playerPtr = player.lock();
610 if (playerPtr != nullptr) {
611 playerPtr->HandleEndOfStreamEvent();
612 }
613 }
614
HandleEndOfStreamEvent()615 void AudioHapticPlayerImpl::HandleEndOfStreamEvent()
616 {
617 std::lock_guard<std::mutex> lock(audioHapticPlayerLock_);
618 if (playerState_ == AudioHapticPlayerState::STATE_RELEASED) {
619 MEDIA_LOGE("The audio haptic player has been released!");
620 return;
621 }
622
623 if (playerState_ == AudioHapticPlayerState::STATE_STOPPED) {
624 MEDIA_LOGE("The audio haptic player has been stopped!");
625 return;
626 }
627
628 if (!loop_.load()) {
629 StopVibrate();
630 playerState_ = AudioHapticPlayerState::STATE_STOPPED;
631 return;
632 }
633
634 // Triggered only if new synchronization is supported.
635 // Low-latency path doesn't trigger EOS during looping; use normal path only.
636 if (isSupportDSPSync_) {
637 audioHapticSyncId_++;
638 }
639 }
640
NotifyErrorEvent(int32_t errCode)641 void AudioHapticPlayerImpl::NotifyErrorEvent(int32_t errCode)
642 {
643 std::shared_ptr<AudioHapticPlayerCallback> cb = audioHapticPlayerCallback_.lock();
644 if (cb != nullptr) {
645 MEDIA_LOGI("NotifyErrorEvent for napi object or caller. errCode: %{public}d", errCode);
646 cb->OnError(errCode);
647 } else {
648 MEDIA_LOGE("NotifyErrorEvent: audioHapticPlayerCallback_ is nullptr");
649 }
650 }
651
NotifyFirstFrame(const uint64_t & latency)652 void AudioHapticPlayerImpl::NotifyFirstFrame(const uint64_t &latency)
653 {
654 NotifyStartVibrate(latency);
655 }
656
NotifyStartVibrate(const uint64_t & latency)657 void AudioHapticPlayerImpl::NotifyStartVibrate(const uint64_t &latency)
658 {
659 if (isVibrationRunning_.load() &&
660 (hapticsMode_ == HapticsMode::HAPTICS_MODE_NON_SYNC_ONCE ||
661 hapticsMode_ == HapticsMode::HAPTICS_MODE_NON_SYNC)) {
662 MEDIA_LOGI("The non sync vibration is already running.");
663 return;
664 }
665 std::lock_guard<std::mutex> lock(this->waitStartVibrateMutex_);
666 this->canStartVibrate_ = true;
667 this->audioLatency_ = latency;
668 this->condStartVibrate_.notify_one();
669 }
670
SendHapticPlayerEvent(const int32_t & errorCode,const std::string & strEvent)671 void AudioHapticPlayerImpl::SendHapticPlayerEvent(const int32_t &errorCode, const std::string &strEvent)
672 {
673 std::shared_ptr<Media::MediaMonitor::EventBean> bean = std::make_shared<Media::MediaMonitor::EventBean>(
674 Media::MediaMonitor::ModuleId::AUDIO, Media::MediaMonitor::EventId::HAPTIC_PLAYER,
675 Media::MediaMonitor::EventType::HAPTIC_PLAYER_EVENT);
676 bean->Add("ERROR_CODE", errorCode);
677 bean->Add("ERROR_REASON", strEvent);
678 Media::MediaMonitor::MediaMonitorManager::GetInstance().WriteLogMsg(bean);
679 }
680
681 // Callback class symbols
AudioHapticSoundCallbackImpl(std::shared_ptr<AudioHapticPlayerImpl> audioHapticPlayerImpl)682 AudioHapticSoundCallbackImpl::AudioHapticSoundCallbackImpl(std::shared_ptr<AudioHapticPlayerImpl> audioHapticPlayerImpl)
683 : audioHapticPlayerImpl_(audioHapticPlayerImpl) {}
684
OnEndOfStream()685 void AudioHapticSoundCallbackImpl::OnEndOfStream()
686 {
687 MEDIA_LOGI("OnEndOfStream reported from audio haptic sound.");
688 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
689 if (player == nullptr) {
690 MEDIA_LOGE("The audio haptic player has been released.");
691 return;
692 }
693 player->NotifyEndOfStreamEvent();
694 }
695
OnError(int32_t errorCode)696 void AudioHapticSoundCallbackImpl::OnError(int32_t errorCode)
697 {
698 MEDIA_LOGE("OnError reported from audio haptic sound: %{public}d", errorCode);
699 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
700 if (player == nullptr) {
701 MEDIA_LOGE("The audio haptic player has been released.");
702 return;
703 }
704 player->NotifyErrorEvent(errorCode);
705 }
706
OnInterrupt(const AudioStandard::InterruptEvent & interruptEvent)707 void AudioHapticSoundCallbackImpl::OnInterrupt(const AudioStandard::InterruptEvent &interruptEvent)
708 {
709 MEDIA_LOGI("OnInterrupt from audio haptic sound. hintType: %{public}d", interruptEvent.hintType);
710 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
711 if (player == nullptr) {
712 MEDIA_LOGE("The audio haptic player has been released.");
713 return;
714 }
715 player->NotifyInterruptEvent(interruptEvent);
716 }
717
OnFirstFrameWriting(uint64_t latency)718 void AudioHapticSoundCallbackImpl::OnFirstFrameWriting(uint64_t latency)
719 {
720 MEDIA_LOGI("OnFirstFrameWriting from audio haptic sound. Latency %{public}" PRIu64 "", latency);
721 std::shared_ptr<AudioHapticPlayerImpl> player = audioHapticPlayerImpl_.lock();
722 if (player == nullptr) {
723 MEDIA_LOGE("The audio haptic player has been released.");
724 return;
725 }
726
727 player->NotifyFirstFrame(latency);
728 }
729 } // namesapce AudioStandard
730 } // namespace OHOS
731