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)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 ¶m)
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