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