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_manager_impl.h"
17
18 #include "audio_haptic_player_impl.h"
19
20 #include "audio_haptic_log.h"
21 #include "media_errors.h"
22
23 #include "isoundpool.h"
24 #include "player.h"
25
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO_NAPI, "AudioHapticManagerImpl"};
28 }
29
30 namespace OHOS {
31 namespace Media {
32 const std::int32_t MAX_PLAYER_NUM = 128;
33 const int32_t ERROR = -1;
34 const std::string FDHEAD = "fd://";
35
36 std::shared_ptr<AudioHapticManager> AudioHapticManagerFactory::audioHapticManager_ = nullptr;
37 std::mutex AudioHapticManagerFactory::audioHapticManagerMutex_;
38
ExtractFd(const std::string & uri)39 static int32_t ExtractFd(const std::string& uri)
40 {
41 if (uri.size() <= FDHEAD.size() || uri.substr(0, FDHEAD.length()) != FDHEAD) {
42 return ERROR;
43 }
44
45 std::string numberPart = uri.substr(FDHEAD.length());
46 for (char c : numberPart) {
47 if (!std::isdigit(c)) {
48 MEDIA_LOGE("ExtractFd: The part after the FDHEAD is not all digits.");
49 return ERROR;
50 }
51 }
52
53 int32_t fd = atoi(numberPart.c_str());
54 return fd > 0 ? fd : ERROR;
55 }
56
DupFdFromUri(const std::string & uri)57 static std::string DupFdFromUri(const std::string &uri)
58 {
59 MEDIA_LOGI("DupFdFromUri uri: %{public}s", uri.c_str());
60 if (uri.find(FDHEAD) == std::string::npos) {
61 return uri;
62 }
63
64 int32_t fd = ExtractFd(uri);
65 if (fd == ERROR) {
66 MEDIA_LOGE("DupFdFromUri ExtractFd failed");
67 return "";
68 }
69
70 int32_t dupFd = dup(fd);
71 if (dupFd == ERROR) {
72 MEDIA_LOGE("DupFdFromUri failed. uri: %{public}s", uri.c_str());
73 return "";
74 }
75 return FDHEAD + std::to_string(dupFd);
76 }
77
CreateAudioHapticManager()78 std::shared_ptr<AudioHapticManager> AudioHapticManagerFactory::CreateAudioHapticManager()
79 {
80 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
81 if (audioHapticManager_ == nullptr) {
82 audioHapticManager_ = std::make_shared<AudioHapticManagerImpl>();
83 }
84 CHECK_AND_RETURN_RET_LOG(audioHapticManager_ != nullptr, nullptr, "Failed to create audio haptic manager object");
85
86 return audioHapticManager_;
87 }
88
AudioHapticManagerImpl()89 AudioHapticManagerImpl::AudioHapticManagerImpl()
90 {
91 audioHapticPlayerMap_.clear();
92 curPlayerIndex_ = 0;
93 curPlayerCount_ = 0;
94 }
95
~AudioHapticManagerImpl()96 AudioHapticManagerImpl::~AudioHapticManagerImpl()
97 {
98 for (auto &[sourceId, info] : audioHapticPlayerMap_) {
99 (void)sourceId;
100 if (!info->audioUri_.empty()) {
101 int32_t fd = ExtractFd(info->audioUri_);
102 if (fd != ERROR) {
103 close(fd);
104 }
105 }
106 if (!info->hapticSource_.hapticUri.empty()) {
107 int32_t fd = ExtractFd(info->hapticSource_.hapticUri);
108 if (fd != ERROR) {
109 close(fd);
110 }
111 }
112 }
113 audioHapticPlayerMap_.clear();
114 curPlayerIndex_ = 0;
115 curPlayerCount_ = 0;
116 }
117
RegisterSourceWithEffectId(const std::string & audioUri,const std::string & effectId)118 int32_t AudioHapticManagerImpl::RegisterSourceWithEffectId(const std::string &audioUri, const std::string &effectId)
119 {
120 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
121 if (effectId == "") {
122 MEDIA_LOGE("RegisterSourceWithEffectId failed. The effectId is empty!");
123 return -1;
124 }
125 if (curPlayerCount_ >= MAX_PLAYER_NUM) {
126 MEDIA_LOGE("RegisterSourceWithEffectId failed. curPlayerCount_: %{public}d", curPlayerCount_);
127 return -1;
128 }
129 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
130 while (audioHapticPlayerMap_[curPlayerIndex_] != nullptr) {
131 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
132 }
133 int32_t sourceId = curPlayerIndex_;
134 HapticSource sourceUri = {"", effectId};
135 audioHapticPlayerMap_[sourceId] = std::make_shared<AudioHapticPlayerInfo>(audioUri, sourceUri,
136 AUDIO_LATENCY_MODE_FAST, AudioStandard::StreamUsage::STREAM_USAGE_MUSIC);
137 curPlayerCount_ += 1;
138 MEDIA_LOGI("Finish to RegisterSourceWithEffectId. effectId: %{public}s, sourceId: %{public}d",
139 effectId.c_str(), sourceId);
140 return sourceId;
141 }
142
RegisterSource(const std::string & audioUri,const std::string & hapticUri)143 int32_t AudioHapticManagerImpl::RegisterSource(const std::string &audioUri, const std::string &hapticUri)
144 {
145 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
146
147 if (curPlayerCount_ >= MAX_PLAYER_NUM) {
148 MEDIA_LOGE("RegisterSource failed curPlayerCount_: %{public}d", curPlayerCount_);
149 return -1;
150 }
151 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
152 while (audioHapticPlayerMap_[curPlayerIndex_] != nullptr) {
153 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
154 }
155 std::string audioUriStr = DupFdFromUri(audioUri);
156 std::string hapticUriStr = DupFdFromUri(hapticUri);
157
158 int32_t sourceId = curPlayerIndex_;
159 HapticSource sourceUri = {hapticUriStr, ""};
160 audioHapticPlayerMap_[sourceId] = std::make_shared<AudioHapticPlayerInfo>(audioUriStr, sourceUri,
161 AUDIO_LATENCY_MODE_NORMAL, AudioStandard::StreamUsage::STREAM_USAGE_MUSIC);
162 curPlayerCount_ += 1;
163 MEDIA_LOGI("Finish to RegisterSource. audioUri: %{public}s, hapticUri: %{public}s, sourceId: %{public}d",
164 audioUriStr.c_str(), hapticUriStr.c_str(), sourceId);
165 return sourceId;
166 }
167
UnregisterSource(const int32_t & sourceID)168 int32_t AudioHapticManagerImpl::UnregisterSource(const int32_t &sourceID)
169 {
170 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
171
172 if (audioHapticPlayerMap_.count(sourceID) == 0 || audioHapticPlayerMap_[sourceID] == nullptr) {
173 MEDIA_LOGE("UnregisterSource failed sourceID: %{public}d", sourceID);
174 return MSERR_INVALID_VAL;
175 }
176
177 std::shared_ptr<AudioHapticPlayerInfo> info = audioHapticPlayerMap_[sourceID];
178 if (!info->audioUri_.empty()) {
179 int32_t fd = ExtractFd(info->audioUri_);
180 if (fd != ERROR) {
181 close(fd);
182 }
183 }
184 if (!info->hapticSource_.hapticUri.empty()) {
185 int32_t fd = ExtractFd(info->hapticSource_.hapticUri);
186 if (fd != ERROR) {
187 close(fd);
188 }
189 }
190
191 audioHapticPlayerMap_[sourceID] = nullptr;
192 audioHapticPlayerMap_.erase(sourceID);
193 curPlayerCount_ -= 1;
194 MEDIA_LOGI("Finish to UnregisterSource. sourceId: %{public}d", sourceID);
195 return MSERR_OK;
196 }
197
CheckAudioLatencyMode(const int32_t & sourceId,const AudioLatencyMode & latencyMode)198 bool AudioHapticManagerImpl::CheckAudioLatencyMode(const int32_t &sourceId, const AudioLatencyMode &latencyMode)
199 {
200 if (latencyMode != AUDIO_LATENCY_MODE_NORMAL && latencyMode != AUDIO_LATENCY_MODE_FAST) {
201 MEDIA_LOGE("The AudioLatencyMode %{public}d is invalid!", latencyMode);
202 return false;
203 }
204
205 // effectId can only be used for low latency mode.
206 HapticSource source = audioHapticPlayerMap_[sourceId]->hapticSource_;
207 if (source.effectId != "" && latencyMode != AUDIO_LATENCY_MODE_FAST) {
208 MEDIA_LOGE("The effectId source can only be used for low latency mode!");
209 return false;
210 }
211
212 return true;
213 }
214
SetAudioLatencyMode(const int32_t & sourceId,const AudioLatencyMode & latencyMode)215 int32_t AudioHapticManagerImpl::SetAudioLatencyMode(const int32_t &sourceId, const AudioLatencyMode &latencyMode)
216 {
217 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
218 if (audioHapticPlayerMap_.count(sourceId) == 0 || audioHapticPlayerMap_[sourceId] == nullptr) {
219 MEDIA_LOGE("SetAudioLatencyMode: failed for invalid sourceID: %{public}d", sourceId);
220 return MSERR_INVALID_VAL;
221 }
222 if (!CheckAudioLatencyMode(sourceId, latencyMode)) {
223 MEDIA_LOGE("SetAudioLatencyMode: failed for invalid latencyMode: %{public}d", latencyMode);
224 return MSERR_INVALID_VAL;
225 }
226 audioHapticPlayerMap_[sourceId]->latencyMode_ = latencyMode;
227 return MSERR_OK;
228 }
229
CheckAudioStreamUsage(const AudioStandard::StreamUsage & streamUsage)230 bool AudioHapticManagerImpl::CheckAudioStreamUsage(const AudioStandard::StreamUsage &streamUsage)
231 {
232 switch (streamUsage) {
233 case AudioStandard::STREAM_USAGE_MUSIC:
234 case AudioStandard::STREAM_USAGE_VOICE_COMMUNICATION:
235 case AudioStandard::STREAM_USAGE_VOICE_ASSISTANT:
236 case AudioStandard::STREAM_USAGE_ALARM:
237 case AudioStandard::STREAM_USAGE_VOICE_MESSAGE:
238 case AudioStandard::STREAM_USAGE_RINGTONE:
239 case AudioStandard::STREAM_USAGE_VOICE_RINGTONE:
240 case AudioStandard::STREAM_USAGE_NOTIFICATION:
241 case AudioStandard::STREAM_USAGE_ACCESSIBILITY:
242 case AudioStandard::STREAM_USAGE_SYSTEM:
243 case AudioStandard::STREAM_USAGE_MOVIE:
244 case AudioStandard::STREAM_USAGE_GAME:
245 case AudioStandard::STREAM_USAGE_AUDIOBOOK:
246 case AudioStandard::STREAM_USAGE_NAVIGATION:
247 case AudioStandard::STREAM_USAGE_DTMF:
248 case AudioStandard::STREAM_USAGE_ENFORCED_TONE:
249 return true;
250 default:
251 break;
252 }
253 MEDIA_LOGE("CheckAudioStreamUsage: streamUsage %{public}d is invalid", streamUsage);
254 return false;
255 }
256
SetStreamUsage(const int32_t & sourceID,const AudioStandard::StreamUsage & streamUsage)257 int32_t AudioHapticManagerImpl::SetStreamUsage(const int32_t &sourceID, const AudioStandard::StreamUsage &streamUsage)
258 {
259 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
260 if (audioHapticPlayerMap_.count(sourceID) == 0 || audioHapticPlayerMap_[sourceID] == nullptr) {
261 MEDIA_LOGE("SetStreamUsage: failed for invalid sourceID: %{public}d", sourceID);
262 return MSERR_INVALID_VAL;
263 }
264 if (!CheckAudioStreamUsage(streamUsage)) {
265 MEDIA_LOGE("SetStreamUsage: failed for invalid latencyMode: %{public}d", streamUsage);
266 return MSERR_INVALID_VAL;
267 }
268 audioHapticPlayerMap_[sourceID]->streamUsage_ = streamUsage;
269 return MSERR_OK;
270 }
271
CreatePlayer(const int32_t & sourceID,const AudioHapticPlayerOptions & audioHapticPlayerOptions)272 std::shared_ptr<AudioHapticPlayer> AudioHapticManagerImpl::CreatePlayer(const int32_t &sourceID,
273 const AudioHapticPlayerOptions &audioHapticPlayerOptions)
274 {
275 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
276 if (audioHapticPlayerMap_.count(sourceID) == 0 || audioHapticPlayerMap_[sourceID] == nullptr) {
277 MEDIA_LOGE("CreatePlayer failed for sourceID: %{public}d", sourceID);
278 return nullptr;
279 }
280
281 std::shared_ptr<AudioHapticPlayerInfo> audioHapticPlayerInfo = audioHapticPlayerMap_[sourceID];
282 AudioHapticPlayerParam param = AudioHapticPlayerParam(audioHapticPlayerOptions,
283 audioHapticPlayerInfo->audioUri_, audioHapticPlayerInfo->hapticSource_,
284 audioHapticPlayerInfo->latencyMode_, audioHapticPlayerInfo->streamUsage_);
285 std::shared_ptr<AudioHapticPlayer> audioHapticPlayer = AudioHapticPlayerFactory::CreateAudioHapticPlayer(param);
286
287 if (audioHapticPlayer == nullptr) {
288 MEDIA_LOGE("CreatePlayer failed for sourceID: %{public}d", sourceID);
289 return nullptr;
290 }
291 return audioHapticPlayer;
292 }
293 } // namesapce AudioStandard
294 } // namespace OHOS
295