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 "media_errors.h"
23
24 namespace {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticVibratorImpl"};
26 #ifdef SUPPORT_VIBRATOR
27 constexpr int32_t MIN_WAITING_TIME_FOR_VIBRATOR = 1200; // ms
28 constexpr uint64_t MILLISECONDS_FOR_ONE_SECOND = 1000; // ms
29 constexpr int32_t PLAYER_BUFFER_TIME = 50; // ms
30 constexpr int32_t MAX_WAITING_LOOP_COUNT = 10;
31 #endif
32 }
33
34 namespace OHOS {
35 namespace Media {
36 #ifdef SUPPORT_VIBRATOR
37 static const std::unordered_map<AudioStandard::StreamUsage, VibratorUsage> USAGE_MAP = {
38 {AudioStandard::StreamUsage::STREAM_USAGE_MEDIA, VibratorUsage::USAGE_MEDIA},
39 {AudioStandard::StreamUsage::STREAM_USAGE_MUSIC, VibratorUsage::USAGE_MEDIA},
40 {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_COMMUNICATION, VibratorUsage::USAGE_COMMUNICATION},
41 {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_ASSISTANT, VibratorUsage::USAGE_MEDIA},
42 {AudioStandard::StreamUsage::STREAM_USAGE_ALARM, VibratorUsage::USAGE_ALARM},
43 {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_MESSAGE, VibratorUsage::USAGE_COMMUNICATION},
44 {AudioStandard::StreamUsage::STREAM_USAGE_NOTIFICATION_RINGTONE, VibratorUsage::USAGE_RING},
45 {AudioStandard::StreamUsage::STREAM_USAGE_RINGTONE, VibratorUsage::USAGE_RING},
46 {AudioStandard::StreamUsage::STREAM_USAGE_VOICE_RINGTONE, VibratorUsage::USAGE_RING},
47 {AudioStandard::StreamUsage::STREAM_USAGE_NOTIFICATION, VibratorUsage::USAGE_NOTIFICATION},
48 {AudioStandard::StreamUsage::STREAM_USAGE_ACCESSIBILITY, VibratorUsage::USAGE_MEDIA},
49 {AudioStandard::StreamUsage::STREAM_USAGE_SYSTEM, VibratorUsage::USAGE_NOTIFICATION},
50 {AudioStandard::StreamUsage::STREAM_USAGE_MOVIE, VibratorUsage::USAGE_MEDIA},
51 {AudioStandard::StreamUsage::STREAM_USAGE_GAME, VibratorUsage::USAGE_MEDIA},
52 {AudioStandard::StreamUsage::STREAM_USAGE_AUDIOBOOK, VibratorUsage::USAGE_MEDIA},
53 {AudioStandard::StreamUsage::STREAM_USAGE_NAVIGATION, VibratorUsage::USAGE_MEDIA},
54 {AudioStandard::StreamUsage::STREAM_USAGE_DTMF, VibratorUsage::USAGE_NOTIFICATION},
55 {AudioStandard::StreamUsage::STREAM_USAGE_ENFORCED_TONE, VibratorUsage::USAGE_NOTIFICATION},
56 {AudioStandard::StreamUsage::STREAM_USAGE_ULTRASONIC, VibratorUsage::USAGE_MEDIA},
57 {AudioStandard::StreamUsage::STREAM_USAGE_VIDEO_COMMUNICATION, VibratorUsage::USAGE_COMMUNICATION},
58 };
59 #endif
60
AudioHapticVibratorImpl(AudioHapticPlayer & audioHapticPlayer)61 AudioHapticVibratorImpl::AudioHapticVibratorImpl(AudioHapticPlayer &audioHapticPlayer)
62 : audioHapticPlayer_(audioHapticPlayer)
63 {
64 if (audioHapticPlayer_.IsMuted(AUDIO_HAPTIC_TYPE_HAPTIC)) {
65 MEDIA_LOGW("The muteHaptic value of audioHapticPlayer_ is true. No need to vibrate.");
66 }
67 }
68
~AudioHapticVibratorImpl()69 AudioHapticVibratorImpl::~AudioHapticVibratorImpl() {}
70
71 std::mutex AudioHapticVibrator::createVibratorMutex_;
72
CreateAudioHapticVibrator(AudioHapticPlayer & audioHapticPlayer)73 std::shared_ptr<AudioHapticVibrator> AudioHapticVibrator::CreateAudioHapticVibrator(
74 AudioHapticPlayer &audioHapticPlayer)
75 {
76 std::lock_guard<std::mutex> lock(createVibratorMutex_);
77 auto audioHapticVibrator = std::make_shared<AudioHapticVibratorImpl>(audioHapticPlayer);
78 return audioHapticVibrator;
79 }
80
SetIsSupportEffectId(bool isSupport)81 void AudioHapticVibratorImpl::SetIsSupportEffectId(bool isSupport)
82 {
83 #ifdef SUPPORT_VIBRATOR
84 isSupportEffectId_ = isSupport;
85 #endif
86 }
87
PreLoad(const HapticSource & hapticSource,const AudioStandard::StreamUsage & streamUsage)88 int32_t AudioHapticVibratorImpl::PreLoad(const HapticSource &hapticSource,
89 const AudioStandard::StreamUsage &streamUsage)
90 {
91 MEDIA_LOGI("PreLoad with hapticUri [%{public}s], effectId [%{public}s], streamUsage [%{public}d]",
92 hapticSource.hapticUri.c_str(), hapticSource.effectId.c_str(), streamUsage);
93 streamUsage_ = streamUsage;
94 #ifdef SUPPORT_VIBRATOR
95 auto iterator = USAGE_MAP.find(streamUsage_);
96 if (iterator != USAGE_MAP.end()) {
97 vibratorUsage_ = iterator->second;
98 } else {
99 MEDIA_LOGW("Invalid stream usage! Use the default usage (USAGE_MEDIA).");
100 vibratorUsage_ = VibratorUsage::USAGE_MEDIA;
101 }
102 hapticSource_ = hapticSource;
103 if (hapticSource.hapticUri == "") {
104 bool isSupported = false;
105 int32_t effectResult = Sensors::IsSupportEffect(hapticSource.effectId.c_str(), &isSupported);
106 if (effectResult == 0 && isSupported) {
107 SetIsSupportEffectId(true);
108 MEDIA_LOGI("The effectId is supported. Vibrator has been prepared.");
109 return MSERR_OK;
110 } else {
111 MEDIA_LOGE("The effectId is not supported!");
112 return MSERR_UNSUPPORT_FILE;
113 }
114 }
115 int32_t fd = open(hapticSource.hapticUri.c_str(), O_RDONLY);
116 if (fd == -1) {
117 // open file failed, return.
118 return MSERR_OPEN_FILE_FAILED;
119 }
120 vibratorFD_ = std::make_shared<VibratorFileDescription>();
121 vibratorPkg_ = std::make_shared<VibratorPackage>();
122
123 struct stat64 statbuf = { 0 };
124 if (fstat64(fd, &statbuf) == 0) {
125 vibratorFD_->fd = fd;
126 vibratorFD_->offset = 0;
127 vibratorFD_->length = statbuf.st_size;
128 } else {
129 return MSERR_OPEN_FILE_FAILED;
130 }
131
132 int32_t result = Sensors::PreProcess(*vibratorFD_, *vibratorPkg_);
133 if (result != 0) {
134 MEDIA_LOGE("PreProcess: %{public}d", result);
135 return MSERR_UNSUPPORT_FILE;
136 }
137 #endif
138 return MSERR_OK;
139 }
140
SetHapticIntensity(float intensity)141 int32_t AudioHapticVibratorImpl::SetHapticIntensity(float intensity)
142 {
143 MEDIA_LOGI("SetHapticIntensity for effectId source. intensity: %{public}f", intensity);
144 std::lock_guard<std::mutex> lock(vibrateMutex_);
145 #ifdef SUPPORT_VIBRATOR
146 vibrateIntensity_ = intensity;
147 #endif
148 return MSERR_OK;
149 }
150
Release()151 int32_t AudioHapticVibratorImpl::Release()
152 {
153 std::lock_guard<std::mutex> lock(vibrateMutex_);
154 isStopped_ = true;
155 #ifdef SUPPORT_VIBRATOR
156 int32_t result = Sensors::Cancel();
157 if (result != 0) {
158 MEDIA_LOGE("Failed to stop vibrator: result %{public}d", result);
159 }
160 vibrateCV_.notify_one();
161
162 if (vibratorPkg_ != nullptr) {
163 Sensors::FreeVibratorPackage(*vibratorPkg_);
164 vibratorPkg_ = nullptr;
165 }
166 vibratorFD_ = nullptr;
167
168 #endif
169 return MSERR_OK;
170 }
171
ResetStopState()172 void AudioHapticVibratorImpl::ResetStopState()
173 {
174 std::lock_guard<std::mutex> lock(vibrateMutex_);
175 isStopped_ = false;
176 }
177
StartVibrate(const AudioLatencyMode & latencyMode)178 int32_t AudioHapticVibratorImpl::StartVibrate(const AudioLatencyMode &latencyMode)
179 {
180 MEDIA_LOGD("StartVibrate: for latency mode %{public}d", latencyMode);
181 int32_t result = MSERR_OK;
182 #ifdef SUPPORT_VIBRATOR
183 if (latencyMode == AUDIO_LATENCY_MODE_NORMAL) {
184 return StartVibrateForAVPlayer();
185 } else if (latencyMode == AUDIO_LATENCY_MODE_FAST) {
186 if (isSupportEffectId_) {
187 std::lock_guard<std::mutex> lock(vibrateMutex_);
188 (void)Sensors::SetUsage(vibratorUsage_);
189 result = Sensors::PlayPrimitiveEffect(hapticSource_.effectId.c_str(), vibrateIntensity_);
190 MEDIA_LOGD("StartVibrate effectId: %{public}s, result: %{public}d", hapticSource_.effectId.c_str(), result);
191 } else {
192 return StartVibrateForSoundPool();
193 }
194 } else {
195 return MSERR_INVALID_OPERATION;
196 }
197 #endif
198 return result;
199 }
200
StartVibrateForSoundPool()201 int32_t AudioHapticVibratorImpl::StartVibrateForSoundPool()
202 {
203 std::unique_lock<std::mutex> lock(vibrateMutex_);
204 if (isStopped_) {
205 MEDIA_LOGW("Vibrator has been stopped. Return ok immediately");
206 return MSERR_OK;
207 }
208
209 int32_t result = MSERR_OK;
210 #ifdef SUPPORT_VIBRATOR
211 if (vibratorPkg_ == nullptr || vibratorFD_ == nullptr) {
212 MEDIA_LOGE("Vibration source file is not prepared. Can not start vibrating");
213 return MSERR_INVALID_OPERATION;
214 }
215 int32_t vibrateTime = 0; // record the pattern time which has been played
216 for (int32_t i = 0; i < vibratorPkg_->patternNum; ++i) {
217 int32_t patternTime = vibratorPkg_->patterns[i].time - vibrateTime; // calculate the time of single pattern
218 vibrateTime = vibratorPkg_->patterns[i].time;
219 (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(patternTime),
220 [this]() { return isStopped_; });
221 CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
222 "StartVibrateForSoundPool: Stop() is call when waiting");
223 (void)Sensors::SetUsage(vibratorUsage_);
224 result = Sensors::PlayPattern(vibratorPkg_->patterns[i]);
225 if (result != 0) {
226 MEDIA_LOGE("StartVibrateForSoundPool: PlayPattern error %{public}d", result);
227 return result;
228 }
229 }
230 #endif
231 return result;
232 }
233
StartVibrateForAVPlayer()234 int32_t AudioHapticVibratorImpl::StartVibrateForAVPlayer()
235 {
236 std::unique_lock<std::mutex> lock(vibrateMutex_);
237 if (isStopped_) {
238 MEDIA_LOGW("Vibrator has been stopped. Return ok immediately");
239 return MSERR_OK;
240 }
241
242 int32_t result = MSERR_OK;
243 #ifdef SUPPORT_VIBRATOR
244 if (vibratorPkg_ == nullptr || vibratorFD_ == nullptr) {
245 MEDIA_LOGE("Vibration source file is not prepared. Can not start vibrating");
246 return MSERR_INVALID_OPERATION;
247 }
248 int32_t vibrateTime = 0; // record the pattern time which has been played
249 for (int32_t i = 0; i < vibratorPkg_->patternNum; ++i) {
250 // the delay time of first frame has been handled in audio haptic player
251 int32_t patternTime = vibratorPkg_->patterns[i].time - vibrateTime; // calculate the time of single pattern
252 (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(patternTime),
253 [this]() { return isStopped_; });
254 CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
255 "StartVibrateForAVPlayer: Stop() is call when waiting");
256 (void)Sensors::SetUsage(vibratorUsage_);
257 result = Sensors::PlayPattern(vibratorPkg_->patterns[i]);
258 CHECK_AND_RETURN_RET_LOG(result == 0, result,
259 "StartVibrateForAVPlayer: PlayPattern error %{public}d", result);
260
261 // get the audio time every second and handle the delay time
262 if (i + 1 >= vibratorPkg_->patternNum) {
263 // the last pattern has been played, break.
264 break;
265 }
266 int32_t nextVibratorTime = vibratorPkg_->patterns[i + 1].time;
267 vibrateTime = audioHapticPlayer_.GetAudioCurrentTime() - PLAYER_BUFFER_TIME + GetDelayTime();
268 int32_t count = 0;
269 while (nextVibratorTime - vibrateTime > MIN_WAITING_TIME_FOR_VIBRATOR && count < MAX_WAITING_LOOP_COUNT) {
270 (void)vibrateCV_.wait_for(lock, std::chrono::milliseconds(MILLISECONDS_FOR_ONE_SECOND),
271 [this]() { return isStopped_; });
272 CHECK_AND_RETURN_RET_LOG(!isStopped_, result,
273 "StartVibrateForAVPlayer: Stop() is call when waiting");
274 vibrateTime = audioHapticPlayer_.GetAudioCurrentTime() - PLAYER_BUFFER_TIME + GetDelayTime();
275 count++;
276 }
277 if (count == MAX_WAITING_LOOP_COUNT) {
278 MEDIA_LOGE("StartVibrateForAVPlayer: loop count has reached the max value.");
279 return MSERR_INVALID_OPERATION;
280 }
281 }
282 #endif
283 return result;
284 }
285
StopVibrate()286 int32_t AudioHapticVibratorImpl::StopVibrate()
287 {
288 std::lock_guard<std::mutex> lock(vibrateMutex_);
289 isStopped_ = true;
290 int32_t result = MSERR_OK;
291 #ifdef SUPPORT_VIBRATOR
292 vibrateCV_.notify_one();
293 result = Sensors::Cancel();
294 MEDIA_LOGI("StopVibrate: %{public}d", result);
295 #endif
296 return result;
297 }
298
GetDelayTime()299 int32_t AudioHapticVibratorImpl::GetDelayTime()
300 {
301 int32_t delayTime = 0;
302 #ifdef SUPPORT_VIBRATOR
303 (void)Sensors::GetDelayTime(delayTime);
304 #endif
305 return delayTime;
306 }
307 } // namesapce Media
308 } // namespace OHOS