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 "system_sound_vibrator.h"
17
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21
22 #ifdef SUPPORT_VIBRATOR
23 #include "vibrator_agent.h"
24 #endif
25
26 #include "media_errors.h"
27 #include "system_sound_log.h"
28
29 namespace {
30 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "SystemSoundVibrator"};
31 }
32
33 namespace OHOS {
34 namespace Media {
35 const std::string PREFIX = "fd://";
36
37 #ifdef SUPPORT_VIBRATOR
38 const std::unordered_map<VibrationType, VibratorUsage> VIBRATOR_USAGE_MAP = {
39 {VibrationType::VIBRATION_RINGTONE, USAGE_RING},
40 {VibrationType::VIBRATION_SYSTEM_TONE, USAGE_NOTIFICATION},
41 };
42
43 const std::unordered_map<VibrationType, int32_t> LOOP_COUNT_MAP = {
44 // Default loop count. Ringtone need be repeated.
45 {VibrationType::VIBRATION_RINGTONE, 10},
46 {VibrationType::VIBRATION_SYSTEM_TONE, 1},
47 };
48
49 const std::unordered_map<VibrationType, std::string> EFFECT_ID_MAP = {
50 // Default effectId
51 {VibrationType::VIBRATION_RINGTONE, "haptic.ringtone.Dream_It_Possible"},
52 {VibrationType::VIBRATION_SYSTEM_TONE, "haptic.pattern.type4"},
53 };
54 #endif
55
StartVibrator(VibrationType type)56 int32_t SystemSoundVibrator::StartVibrator(VibrationType type)
57 {
58 MEDIA_LOGD("StartVibrator: for vibration type %{public}d", type);
59 int32_t result = MSERR_OK;
60 #ifdef SUPPORT_VIBRATOR
61 bool setUsageRet = Sensors::SetUsage(VIBRATOR_USAGE_MAP.at(type));
62 bool setLoopRet = Sensors::SetLoopCount(LOOP_COUNT_MAP.at(type));
63 result = Sensors::StartVibrator(EFFECT_ID_MAP.at(type).c_str());
64 MEDIA_LOGI("StartVibrator: setUsageRet %{public}d, setLoopRet %{public}d, startRet %{public}d",
65 setUsageRet, setLoopRet, result);
66 #endif
67 return result;
68 }
69
StartVibratorForSystemTone(const std::string & hapticUri)70 int32_t SystemSoundVibrator::StartVibratorForSystemTone(const std::string &hapticUri)
71 {
72 MEDIA_LOGI("Start vibrator with hapticUri %{public}s", hapticUri.c_str());
73 int32_t result = MSERR_OK;
74 #ifdef SUPPORT_VIBRATOR
75 if (!(Sensors::IsSupportVibratorCustom())) {
76 MEDIA_LOGE("Custom vibration is not supported for this device!");
77 return MSERR_INVALID_OPERATION;
78 }
79 int32_t fd = ExtractFd(hapticUri);
80 if (fd == -1) {
81 MEDIA_LOGI("hapticUri is not fd. Try to open it");
82 char realPathRes[PATH_MAX + 1] = {'\0'};
83 CHECK_AND_RETURN_RET_LOG((strlen(hapticUri.c_str()) < PATH_MAX) &&
84 (realpath(hapticUri.c_str(), realPathRes) != nullptr), MSERR_OPEN_FILE_FAILED, "Invalid file path length");
85 std::string realPathStr(realPathRes);
86 fd = open(realPathStr.c_str(), O_RDONLY);
87 if (fd == -1) {
88 MEDIA_LOGE("Failed to open hapticUri!");
89 return MSERR_OPEN_FILE_FAILED;
90 }
91 }
92
93 struct stat64 statbuf = { 0 };
94 if (fstat64(fd, &statbuf) != 0) {
95 MEDIA_LOGE("Failed to open fd and get size.");
96 close(fd);
97 return MSERR_OPEN_FILE_FAILED;
98 }
99 Sensors::SetUsage(USAGE_NOTIFICATION);
100 Sensors::SetLoopCount(1);
101 result = Sensors::PlayVibratorCustom(fd, 0, statbuf.st_size);
102 close(fd);
103 #endif
104
105 return result;
106 }
107
ExtractFd(const std::string & hapticsUri)108 int32_t SystemSoundVibrator::ExtractFd(const std::string& hapticsUri)
109 {
110 if (hapticsUri.size() <= PREFIX.size() || hapticsUri.substr(0, PREFIX.length()) != PREFIX) {
111 MEDIA_LOGW("ExtractFd: Input does not start with the required PREFIX.");
112 return -1;
113 }
114
115 std::string numberPart = hapticsUri.substr(PREFIX.length());
116 for (char c : numberPart) {
117 if (!std::isdigit(c)) {
118 MEDIA_LOGE("ExtractFd: The part after the PREFIX is not all digits.");
119 return -1;
120 }
121 }
122 return std::stoi(numberPart);
123 }
124
StopVibrator()125 int32_t SystemSoundVibrator::StopVibrator()
126 {
127 int32_t result = MSERR_OK;
128 #ifdef SUPPORT_VIBRATOR
129 result = Sensors::Cancel();
130 MEDIA_LOGI("StopVibrator: %{public}d", result);
131 #endif
132 return result;
133 }
134 } // namesapce AudioStandard
135 } // namespace OHOS
136