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_vibrator_impl.h"
17 
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 
21 #include "audio_haptic_log.h"
22 #include "directory_ex.h"
23 #include "media_errors.h"
24 
25 namespace {
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticVibratorImpl"};
27 #ifdef SUPPORT_VIBRATOR
28 constexpr int32_t MIN_WAITING_TIME_FOR_VIBRATOR = 1200; // ms
29 constexpr uint64_t MILLISECONDS_FOR_ONE_SECOND = 1000; // ms
30 constexpr int32_t PLAYER_BUFFER_TIME = 50; // ms
31 constexpr int32_t MAX_WAITING_LOOP_COUNT = 10;
32 #endif
33 }
34 
35 namespace OHOS {
36 namespace Media {
37 #ifdef SUPPORT_VIBRATOR
38 static const std::unordered_map<AudioStandard::StreamUsage, VibratorUsage> USAGE_MAP = {
39     {AudioStandard::StreamUsage::STREAM_USAGE_MEDIA, VibratorUsage::USAGE_MEDIA},
40     {AudioStandard::StreamUsage::STREAM_USAGE_MUSIC, VibratorUsage::USAGE_MEDIA},
41     {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_COMMUNICATION, VibratorUsage::USAGE_COMMUNICATION},
42     {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_ASSISTANT, VibratorUsage::USAGE_MEDIA},
43     {AudioStandard::StreamUsage::STREAM_USAGE_ALARM, VibratorUsage::USAGE_ALARM},
44     {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_MESSAGE, VibratorUsage::USAGE_COMMUNICATION},
45     {AudioStandard::StreamUsage::STREAM_USAGE_NOTIFICATION_RINGTONE, VibratorUsage::USAGE_RING},
46     {AudioStandard::StreamUsage::STREAM_USAGE_RINGTONE, VibratorUsage::USAGE_RING},
47     {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_RINGTONE, VibratorUsage::USAGE_RING},
48     {AudioStandard::StreamUsage::STREAM_USAGE_NOTIFICATION, VibratorUsage::USAGE_NOTIFICATION},
49     {AudioStandard::StreamUsage::STREAM_USAGE_ACCESSIBILITY, VibratorUsage::USAGE_MEDIA},
50     {AudioStandard::StreamUsage::STREAM_USAGE_SYSTEM, VibratorUsage::USAGE_NOTIFICATION},
51     {AudioStandard::StreamUsage::STREAM_USAGE_MOVIE, VibratorUsage::USAGE_MEDIA},
52     {AudioStandard::StreamUsage::STREAM_USAGE_GAME, VibratorUsage::USAGE_MEDIA},
53     {AudioStandard::StreamUsage::STREAM_USAGE_AUDIOBOOK, VibratorUsage::USAGE_MEDIA},
54     {AudioStandard::StreamUsage::STREAM_USAGE_NAVIGATION, VibratorUsage::USAGE_MEDIA},
55     {AudioStandard::StreamUsage::STREAM_USAGE_DTMF, VibratorUsage::USAGE_NOTIFICATION},
56     {AudioStandard::StreamUsage::STREAM_USAGE_ENFORCED_TONE, VibratorUsage::USAGE_NOTIFICATION},
57     {AudioStandard::StreamUsage::STREAM_USAGE_ULTRASONIC, VibratorUsage::USAGE_MEDIA},
58     {AudioStandard::StreamUsage::STREAM_USAGE_VIDEO_COMMUNICATION, VibratorUsage::USAGE_COMMUNICATION},
59 };
60 #endif
61 const int ERROR = -1;
62 
AudioHapticVibratorImpl(AudioHapticPlayer & audioHapticPlayer)63 AudioHapticVibratorImpl::AudioHapticVibratorImpl(AudioHapticPlayer &audioHapticPlayer)
64     : audioHapticPlayer_(audioHapticPlayer)
65 {
66     if (audioHapticPlayer_.IsMuted(AUDIO_HAPTIC_TYPE_HAPTIC)) {
67         MEDIA_LOGW("The muteHaptic value of audioHapticPlayer_ is true. No need to vibrate.");
68     }
69 }
70 
~AudioHapticVibratorImpl()71 AudioHapticVibratorImpl::~AudioHapticVibratorImpl() {}
72 
73 std::mutex AudioHapticVibrator::createVibratorMutex_;
74 
CreateAudioHapticVibrator(AudioHapticPlayer & audioHapticPlayer)75 std::shared_ptr<AudioHapticVibrator> AudioHapticVibrator::CreateAudioHapticVibrator(
76     AudioHapticPlayer &audioHapticPlayer)
77 {
78     std::lock_guard<std::mutex> lock(createVibratorMutex_);
79     auto audioHapticVibrator = std::make_shared<AudioHapticVibratorImpl>(audioHapticPlayer);
80     return audioHapticVibrator;
81 }
82 
SetIsSupportEffectId(bool isSupport)83 void AudioHapticVibratorImpl::SetIsSupportEffectId(bool isSupport)
84 {
85 #ifdef SUPPORT_VIBRATOR
86     isSupportEffectId_ = isSupport;
87 #endif
88 }
89 
ExtractFd(const std::string & hapticsUri)90 int32_t AudioHapticVibratorImpl::ExtractFd(const std::string& hapticsUri)
91 {
92     const std::string prefix = "fd://";
93     if (hapticsUri.size() <= prefix.size() || hapticsUri.substr(0, prefix.length()) != prefix) {
94         MEDIA_LOGW("ExtractFd: Input does not start with the required prefix.");
95         return ERROR;
96     }
97 
98     std::string numberPart = hapticsUri.substr(prefix.length());
99     for (char c : numberPart) {
100         if (!std::isdigit(c)) {
101             MEDIA_LOGE("ExtractFd: The part after the prefix is not all digits.");
102             return ERROR;
103         }
104     }
105 
106     int32_t fd = atoi(numberPart.c_str());
107     return fd > 0 ? fd : ERROR;
108 }
109 
OpenHapticFile(const std::string & hapticUri)110 int32_t AudioHapticVibratorImpl::OpenHapticFile(const std::string &hapticUri)
111 {
112 #ifdef SUPPORT_VIBRATOR
113     int32_t newFd = -1;
114     int32_t oldFd = ExtractFd(hapticUri);
115     if (oldFd != ERROR) {
116         newFd = dup(oldFd);
117         if (newFd == ERROR) {
118             MEDIA_LOGE("OpenHapticFile: dup failed, file path: %{public}s", hapticUri.c_str());
119             return MSERR_OPEN_FILE_FAILED;
120         }
121     } else {
122         MEDIA_LOGW("OpenHapticFile: hapticUri is not new format.");
123 
124         std::string absFilePath;
125         if (!PathToRealPath(hapticUri, absFilePath)) {
126             MEDIA_LOGE("file is not real path, file path: %{private}s", hapticUri.c_str());
127             return ERROR;
128         }
129         if (absFilePath.empty()) {
130             MEDIA_LOGE("Failed to obtain the canonical path for source path %{public}d %{private}s",
131                 errno, hapticUri.c_str());
132             return ERROR;
133         }
134 
135         newFd = open(hapticUri.c_str(), O_RDONLY);
136         if (newFd == ERROR) {
137             // open file failed, return.
138             MEDIA_LOGE("OpenHapticFile: open file failed, file path: %{public}s", hapticUri.c_str());
139             return MSERR_OPEN_FILE_FAILED;
140         }
141     }
142 
143     vibratorFD_ = std::make_shared<VibratorFileDescription>();
144     CHECK_AND_RETURN_RET_LOG(vibratorFD_ != nullptr, ERROR, "vibratorFD_ is null");
145     vibratorPkg_ = std::make_shared<VibratorPackage>();
146     CHECK_AND_RETURN_RET_LOG(vibratorPkg_ != nullptr, ERROR, "vibratorPkg_ is null");
147 
148     struct stat64 statbuf = { 0 };
149     if (fstat64(newFd, &statbuf) == 0) {
150         vibratorFD_->fd = newFd;
151         vibratorFD_->offset = 0;
152         vibratorFD_->length = statbuf.st_size;
153         return MSERR_OK;
154     } else {
155         close(newFd);
156         return MSERR_OPEN_FILE_FAILED;
157     }
158 #endif
159     return MSERR_OK;
160 }
161 
PreLoad(const HapticSource & hapticSource,const AudioStandard::StreamUsage & streamUsage)162 int32_t AudioHapticVibratorImpl::PreLoad(const HapticSource &hapticSource,
163     const AudioStandard::StreamUsage &streamUsage)
164 {
165     MEDIA_LOGI("PreLoad with hapticUri [%{public}s], effectId [%{public}s], streamUsage [%{public}d]",
166         hapticSource.hapticUri.c_str(), hapticSource.effectId.c_str(), streamUsage);
167     streamUsage_ = streamUsage;
168 #ifdef SUPPORT_VIBRATOR
169     if (audioHapticPlayer_.GetHapticsMode() == HapticsMode::HAPTICS_MODE_NONE) {
170         MEDIA_LOGI("The hapticdMopde value of audioHapticPlayer_ is NONE. No need to vibrate.");
171         return MSERR_OK;
172     }
173     auto iterator = USAGE_MAP.find(streamUsage_);
174     if (iterator != USAGE_MAP.end()) {
175         vibratorUsage_ = iterator->second;
176     } else {
177         MEDIA_LOGW("Invalid stream usage! Use the default usage (USAGE_MEDIA).");
178         vibratorUsage_ = VibratorUsage::USAGE_MEDIA;
179     }
180     hapticSource_ = hapticSource;
181     if (hapticSource.hapticUri == "") {
182         bool isSupported = false;
183         int32_t effectResult = Sensors::IsSupportEffect(hapticSource.effectId.c_str(), &isSupported);
184         if (effectResult == 0 && isSupported) {
185             SetIsSupportEffectId(true);
186             MEDIA_LOGI("The effectId is supported. Vibrator has been prepared.");
187             return MSERR_OK;
188         } else {
189             MEDIA_LOGE("The effectId is not supported!");
190             return MSERR_UNSUPPORT_FILE;
191         }
192     }
193 
194     if (OpenHapticFile(hapticSource.hapticUri) != MSERR_OK) {
195         return MSERR_OPEN_FILE_FAILED;
196     }
197 
198     int32_t result = Sensors::PreProcess(*vibratorFD_, *vibratorPkg_);
199     if (result != 0) {
200         return MSERR_UNSUPPORT_FILE;
201     }
202 #endif
203     return MSERR_OK;
204 }
205 
SetHapticIntensity(float intensity)206 int32_t AudioHapticVibratorImpl::SetHapticIntensity(float intensity)
207 {
208     MEDIA_LOGI("SetHapticIntensity for effectId source. intensity: %{public}f", intensity);
209     std::lock_guard<std::mutex> lock(vibrateMutex_);
210 #ifdef SUPPORT_VIBRATOR
211     vibrateIntensity_ = intensity;
212 #endif
213     return MSERR_OK;
214 }
215 
Release()216 int32_t AudioHapticVibratorImpl::Release()
217 {
218     std::lock_guard<std::mutex> lock(vibrateMutex_);
219     isStopped_ = true;
220 #ifdef SUPPORT_VIBRATOR
221     int32_t result = Sensors::Cancel();
222     if (result != 0) {
223         MEDIA_LOGE("Failed to stop vibrator: result %{public}d", result);
224     }
225     vibrateCV_.notify_one();
226 
227     if (vibratorPkg_ != nullptr) {
228         Sensors::FreeVibratorPackage(*vibratorPkg_);
229         vibratorPkg_ = nullptr;
230     }
231     vibratorFD_ = nullptr;
232 
233 #endif
234     return MSERR_OK;
235 }
236 
ResetStopState()237 void AudioHapticVibratorImpl::ResetStopState()
238 {
239     std::lock_guard<std::mutex> lock(vibrateMutex_);
240     isStopped_ = false;
241 }
242 
StartVibrate(const AudioLatencyMode & latencyMode)243 int32_t AudioHapticVibratorImpl::StartVibrate(const AudioLatencyMode &latencyMode)
244 {
245     MEDIA_LOGI("StartVibrate: for latency mode %{public}d", latencyMode);
246     int32_t result = MSERR_OK;
247 #ifdef SUPPORT_VIBRATOR
248     if (audioHapticPlayer_.GetHapticsMode() == HapticsMode::HAPTICS_MODE_NONE) {
249         return result;
250     } else if (audioHapticPlayer_.GetHapticsMode() == HapticsMode::HAPTICS_MODE_NON_SYNC) {
251         return StartNonSyncVibration();
252     }
253     if (latencyMode == AUDIO_LATENCY_MODE_NORMAL) {
254         return StartVibrateForAVPlayer();
255     } else if (latencyMode == AUDIO_LATENCY_MODE_FAST) {
256         if (isSupportEffectId_) {
257             return StartVibrateWithEffect();
258         } else {
259             return StartVibrateForSoundPool();
260         }
261     } else {
262         return MSERR_INVALID_OPERATION;
263     }
264 #endif
265     return result;
266 }
267 
StartVibrateWithEffect()268 int32_t AudioHapticVibratorImpl::StartVibrateWithEffect()
269 {
270     int32_t result = MSERR_OK;
271 #ifdef SUPPORT_VIBRATOR
272     std::lock_guard<std::mutex> lock(vibrateMutex_);
273     (void)Sensors::SetUsage(vibratorUsage_);
274     MEDIA_LOGI("PlayPrimitiveEffect with effectId: %{public}s", hapticSource_.effectId.c_str());
275     result = Sensors::PlayPrimitiveEffect(hapticSource_.effectId.c_str(), vibrateIntensity_);
276     if (result != 0) {
277         MEDIA_LOGE("Failed to PlayPrimitiveEffect with effectId: %{public}s, result: %{public}d",
278             hapticSource_.effectId.c_str(), result);
279     }
280 #endif
281     return result;
282 }
283 
StartVibrateForSoundPool()284 int32_t AudioHapticVibratorImpl::StartVibrateForSoundPool()
285 {
286     std::unique_lock<std::mutex> lock(vibrateMutex_);
287     if (isStopped_) {
288         MEDIA_LOGW("Vibrator has been stopped. Return ok immediately");
289         return MSERR_OK;
290     }
291 
292     int32_t result = MSERR_OK;
293 #ifdef SUPPORT_VIBRATOR
294     if (vibratorPkg_ == nullptr || vibratorFD_ == nullptr) {
295         MEDIA_LOGE("Vibration source file is not prepared. Can not start vibrating");
296         return MSERR_INVALID_OPERATION;
297     }
298     int32_t vibrateTime = 0; // record the pattern time which has been played
299     for (int32_t i = 0; i < vibratorPkg_->patternNum; ++i) {
300         int32_t patternTime = vibratorPkg_->patterns[i].time - vibrateTime; // calculate the time of single pattern
301         vibrateTime = vibratorPkg_->patterns[i].time;
302         (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(patternTime),
303             [this]() { return isStopped_; });
304         CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
305             "StartVibrateForSoundPool: Stop() is call when waiting");
306         (void)Sensors::SetUsage(vibratorUsage_);
307         MEDIA_LOGI("PlayPattern for SoundPool.");
308         result = Sensors::PlayPattern(vibratorPkg_->patterns[i]);
309         if (result != 0) {
310             MEDIA_LOGE("Failed to PlayPattern for SoundPool. Error %{public}d", result);
311             return result;
312         }
313     }
314 #endif
315     return result;
316 }
317 
RunVibrationPatterns(std::unique_lock<std::mutex> & lock)318 int32_t AudioHapticVibratorImpl::RunVibrationPatterns(std::unique_lock<std::mutex> &lock)
319 {
320     int32_t result = MSERR_OK;
321 #ifdef SUPPORT_VIBRATOR
322     int32_t vibrateTime = 0; // record the pattern time which has been played
323     for (int32_t i = 0; i < vibratorPkg_->patternNum; ++i) {
324         int32_t patternTime = vibratorPkg_->patterns[i].time - vibrateTime; // calculate the time of single pattern
325         vibrateTime = vibratorPkg_->patterns[i].time;
326         (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(patternTime),
327             [this]() { return isStopped_; });
328         CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
329             "RunVibrationPatterns: Stop() is call when waiting");
330         (void)Sensors::SetUsage(vibratorUsage_);
331         MEDIA_LOGI("PlayPattern for NonSyncVibration");
332         result = Sensors::PlayPattern(vibratorPkg_->patterns[i]);
333         if (result != 0) {
334             MEDIA_LOGE("Failed to PlayPattern for NonSyncVibration. Error %{public}d", result);
335             return result;
336         }
337         if (i == vibratorPkg_->patternNum - 1) {
338             int32_t lastPatternDuration = vibratorPkg_->patterns[i].patternDuration;
339             (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(lastPatternDuration),
340                 [this]() { return isStopped_; });
341             CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
342                 "RunVibrationPatterns: Stop() is call when waiting");
343         }
344     }
345 #endif
346     return result;
347 }
348 
StartNonSyncVibration()349 int32_t AudioHapticVibratorImpl::StartNonSyncVibration()
350 {
351     std::unique_lock<std::mutex> lock(vibrateMutex_);
352     if (isStopped_) {
353         MEDIA_LOGW("Vibrator has been stopped. Return ok immediately");
354         return MSERR_OK;
355     }
356 
357     int32_t result = MSERR_OK;
358 #ifdef SUPPORT_VIBRATOR
359     if (vibratorPkg_ == nullptr || vibratorFD_ == nullptr) {
360         MEDIA_LOGE("Vibration source file is not prepared. Can not start vibrating");
361         return MSERR_INVALID_OPERATION;
362     }
363     while (!isStopped_) {
364         result = RunVibrationPatterns(lock);
365         if (result != MSERR_OK) {
366             MEDIA_LOGI("StartNonSyncVibration: RunVibrationPatterns fail.");
367             return result;
368         }
369     }
370 #endif
371     return result;
372 }
373 
StartVibrateForAVPlayer()374 int32_t AudioHapticVibratorImpl::StartVibrateForAVPlayer()
375 {
376     std::unique_lock<std::mutex> lock(vibrateMutex_);
377     if (isStopped_) {
378         MEDIA_LOGW("Vibrator has been stopped. Return ok immediately");
379         return MSERR_OK;
380     }
381 
382     int32_t result = MSERR_OK;
383 #ifdef SUPPORT_VIBRATOR
384     if (vibratorPkg_ == nullptr || vibratorFD_ == nullptr) {
385         MEDIA_LOGE("Vibration source file is not prepared. Can not start vibrating");
386         return MSERR_INVALID_OPERATION;
387     }
388     int32_t vibrateTime = 0; // record the pattern time which has been played
389     for (int32_t i = 0; i < vibratorPkg_->patternNum; ++i) {
390         // the delay time of first frame has been handled in audio haptic player
391         int32_t patternTime = vibratorPkg_->patterns[i].time - vibrateTime; // calculate the time of single pattern
392         (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(patternTime),
393             [this]() { return isStopped_; });
394         CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
395             "StartVibrateForAVPlayer: Stop() is call when waiting");
396         (void)Sensors::SetUsage(vibratorUsage_);
397         MEDIA_LOGI("PlayPattern for AVPlayer successfully!");
398         result = Sensors::PlayPattern(vibratorPkg_->patterns[i]);
399         CHECK_AND_RETURN_RET_LOG(result == 0, result,
400             "Failed to PlayPattern for AVPlayer. Error %{public}d", result);
401 
402         // get the audio time every second and handle the delay time
403         if (i + 1 >= vibratorPkg_->patternNum) {
404             // the last pattern has been played, break.
405             break;
406         }
407         int32_t nextVibratorTime = vibratorPkg_->patterns[i + 1].time;
408         vibrateTime = audioHapticPlayer_.GetAudioCurrentTime() - PLAYER_BUFFER_TIME + GetDelayTime();
409         int32_t count = 0;
410         while (nextVibratorTime - vibrateTime > MIN_WAITING_TIME_FOR_VIBRATOR && count < MAX_WAITING_LOOP_COUNT) {
411             (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(MILLISECONDS_FOR_ONE_SECOND),
412                 [this]() { return isStopped_; });
413             CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
414                 "StartVibrateForAVPlayer: Stop() is call when waiting");
415             vibrateTime = audioHapticPlayer_.GetAudioCurrentTime() - PLAYER_BUFFER_TIME + GetDelayTime();
416             count++;
417         }
418         if (count == MAX_WAITING_LOOP_COUNT) {
419             MEDIA_LOGE("StartVibrateForAVPlayer: loop count has reached the max value.");
420             return MSERR_INVALID_OPERATION;
421         }
422     }
423 #endif
424     return result;
425 }
426 
StopVibrate()427 int32_t AudioHapticVibratorImpl::StopVibrate()
428 {
429     std::lock_guard<std::mutex> lock(vibrateMutex_);
430     isStopped_ = true;
431     int32_t result = MSERR_OK;
432 #ifdef SUPPORT_VIBRATOR
433     vibrateCV_.notify_one();
434     result = Sensors::Cancel();
435     MEDIA_LOGI("StopVibrate: %{public}d", result);
436 #endif
437     return result;
438 }
439 
GetDelayTime()440 int32_t AudioHapticVibratorImpl::GetDelayTime()
441 {
442     int32_t delayTime = 0;
443 #ifdef SUPPORT_VIBRATOR
444     (void)Sensors::GetDelayTime(delayTime);
445 #endif
446     return delayTime;
447 }
448 } // namesapce Media
449 } // namespace OHOS