• 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_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