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