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