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 ReleasePlayerInfo(info);
101 }
102 audioHapticPlayerMap_.clear();
103 curPlayerIndex_ = 0;
104 curPlayerCount_ = 0;
105 }
106
RegisterSourceWithEffectId(const std::string & audioUri,const std::string & effectId)107 int32_t AudioHapticManagerImpl::RegisterSourceWithEffectId(const std::string &audioUri, const std::string &effectId)
108 {
109 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
110 if (effectId == "") {
111 MEDIA_LOGE("RegisterSourceWithEffectId failed. The effectId is empty!");
112 return INVALID_SOURCE_ID;
113 }
114 if (curPlayerCount_ >= MAX_PLAYER_NUM) {
115 MEDIA_LOGE("RegisterSourceWithEffectId failed. curPlayerCount_: %{public}d", curPlayerCount_);
116 return INVALID_SOURCE_ID;
117 }
118 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
119 while (audioHapticPlayerMap_[curPlayerIndex_] != nullptr) {
120 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
121 }
122 int32_t sourceId = curPlayerIndex_;
123 AudioSource audioSrc = {.audioUri = audioUri};
124 HapticSource hapticSrc = {.effectId = effectId};
125 audioHapticPlayerMap_[sourceId] = std::make_shared<AudioHapticPlayerInfo>(audioSrc, hapticSrc,
126 AUDIO_LATENCY_MODE_FAST, AudioStandard::StreamUsage::STREAM_USAGE_MUSIC);
127 curPlayerCount_ += 1;
128 MEDIA_LOGI("Finish to RegisterSourceWithEffectId. effectId: %{public}s, sourceId: %{public}d",
129 effectId.c_str(), sourceId);
130 return sourceId;
131 }
132
RegisterSource(const std::string & audioUri,const std::string & hapticUri)133 int32_t AudioHapticManagerImpl::RegisterSource(const std::string &audioUri, const std::string &hapticUri)
134 {
135 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
136
137 if (curPlayerCount_ >= MAX_PLAYER_NUM) {
138 MEDIA_LOGE("RegisterSource failed curPlayerCount_: %{public}d", curPlayerCount_);
139 return INVALID_SOURCE_ID;
140 }
141 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
142 while (audioHapticPlayerMap_[curPlayerIndex_] != nullptr) {
143 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
144 }
145 std::string audioUriStr = DupFdFromUri(audioUri);
146 std::string hapticUriStr = DupFdFromUri(hapticUri);
147
148 int32_t sourceId = curPlayerIndex_;
149 AudioSource audioSrc = {.audioUri = audioUriStr};
150 HapticSource hapticSrc = {.hapticUri = hapticUriStr};
151 audioHapticPlayerMap_[sourceId] = std::make_shared<AudioHapticPlayerInfo>(audioSrc, hapticSrc,
152 AUDIO_LATENCY_MODE_NORMAL, AudioStandard::StreamUsage::STREAM_USAGE_MUSIC);
153 curPlayerCount_ += 1;
154 MEDIA_LOGI("Finish to RegisterSource. audioUri: %{public}s, hapticUri: %{public}s, sourceId: %{public}d",
155 audioUriStr.c_str(), hapticUriStr.c_str(), sourceId);
156 return sourceId;
157 }
158
RegisterSourceFromFd(const AudioHapticFileDescriptor & audioFd,const AudioHapticFileDescriptor & hapticFd)159 int32_t AudioHapticManagerImpl::RegisterSourceFromFd(const AudioHapticFileDescriptor& audioFd,
160 const AudioHapticFileDescriptor& hapticFd)
161 {
162 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
163 if (curPlayerCount_ >= MAX_PLAYER_NUM) {
164 MEDIA_LOGE("RegisterSourceFromFd failed curPlayerCount_: %{public}d", curPlayerCount_);
165 return INVALID_SOURCE_ID;
166 }
167 int32_t newAudioFd = dup(audioFd.fd);
168 if (newAudioFd == FILE_DESCRIPTOR_INVALID) {
169 MEDIA_LOGE("RegisterSourceFromFd failed invalid audio fd");
170 return INVALID_SOURCE_ID;
171 }
172 int32_t newHapticFd = dup(hapticFd.fd);
173 if (newHapticFd == FILE_DESCRIPTOR_INVALID) {
174 MEDIA_LOGE("RegisterSourceFromFd failed invalid haptic fd");
175 return INVALID_SOURCE_ID;
176 }
177
178 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
179 while (audioHapticPlayerMap_[curPlayerIndex_] != nullptr) {
180 curPlayerIndex_ = (curPlayerIndex_ + 1) % MAX_PLAYER_NUM;
181 }
182 int32_t sourceId = curPlayerIndex_;
183 AudioSource audioSrc = {.fd = newAudioFd, .length = audioFd.length, .offset = audioFd.offset};
184 HapticSource hapticSrc = {.fd = newHapticFd, .length = hapticFd.length, .offset = hapticFd.offset};
185 audioHapticPlayerMap_[sourceId] = std::make_shared<AudioHapticPlayerInfo>(audioSrc, hapticSrc,
186 AUDIO_LATENCY_MODE_NORMAL, AudioStandard::StreamUsage::STREAM_USAGE_MUSIC);
187 curPlayerCount_ += 1;
188 MEDIA_LOGI("audioFd: %{public}d, hapticeFd: %{public}d, sourceId: %{public}d",
189 audioFd.fd, hapticFd.fd, sourceId);
190 return sourceId;
191 }
192
UnregisterSource(const int32_t & sourceID)193 int32_t AudioHapticManagerImpl::UnregisterSource(const int32_t &sourceID)
194 {
195 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
196
197 if (audioHapticPlayerMap_.count(sourceID) == 0 || audioHapticPlayerMap_[sourceID] == nullptr) {
198 MEDIA_LOGE("UnregisterSource failed sourceID: %{public}d", sourceID);
199 return MSERR_INVALID_VAL;
200 }
201
202 std::shared_ptr<AudioHapticPlayerInfo> info = audioHapticPlayerMap_[sourceID];
203 ReleasePlayerInfo(info);
204
205 audioHapticPlayerMap_[sourceID] = nullptr;
206 audioHapticPlayerMap_.erase(sourceID);
207 curPlayerCount_ -= 1;
208 MEDIA_LOGI("Finish to UnregisterSource. sourceId: %{public}d", sourceID);
209 return MSERR_OK;
210 }
211
CheckAudioLatencyMode(const int32_t & sourceId,const AudioLatencyMode & latencyMode)212 bool AudioHapticManagerImpl::CheckAudioLatencyMode(const int32_t &sourceId, const AudioLatencyMode &latencyMode)
213 {
214 if (latencyMode != AUDIO_LATENCY_MODE_NORMAL && latencyMode != AUDIO_LATENCY_MODE_FAST) {
215 MEDIA_LOGE("The AudioLatencyMode %{public}d is invalid!", latencyMode);
216 return false;
217 }
218
219 // effectId can only be used for low latency mode.
220 HapticSource source = audioHapticPlayerMap_[sourceId]->hapticSource_;
221 if (source.effectId != "" && latencyMode != AUDIO_LATENCY_MODE_FAST) {
222 MEDIA_LOGE("The effectId source can only be used for low latency mode!");
223 return false;
224 }
225
226 return true;
227 }
228
SetAudioLatencyMode(const int32_t & sourceId,const AudioLatencyMode & latencyMode)229 int32_t AudioHapticManagerImpl::SetAudioLatencyMode(const int32_t &sourceId, const AudioLatencyMode &latencyMode)
230 {
231 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
232 if (audioHapticPlayerMap_.count(sourceId) == 0 || audioHapticPlayerMap_[sourceId] == nullptr) {
233 MEDIA_LOGE("SetAudioLatencyMode: failed for invalid sourceID: %{public}d", sourceId);
234 return MSERR_INVALID_VAL;
235 }
236 if (!CheckAudioLatencyMode(sourceId, latencyMode)) {
237 MEDIA_LOGE("SetAudioLatencyMode: failed for invalid latencyMode: %{public}d", latencyMode);
238 return MSERR_INVALID_VAL;
239 }
240 audioHapticPlayerMap_[sourceId]->latencyMode_ = latencyMode;
241 return MSERR_OK;
242 }
243
CheckAudioStreamUsage(const AudioStandard::StreamUsage & streamUsage)244 bool AudioHapticManagerImpl::CheckAudioStreamUsage(const AudioStandard::StreamUsage &streamUsage)
245 {
246 switch (streamUsage) {
247 case AudioStandard::STREAM_USAGE_MUSIC:
248 case AudioStandard::STREAM_USAGE_VOICE_COMMUNICATION:
249 case AudioStandard::STREAM_USAGE_VOICE_ASSISTANT:
250 case AudioStandard::STREAM_USAGE_ALARM:
251 case AudioStandard::STREAM_USAGE_VOICE_MESSAGE:
252 case AudioStandard::STREAM_USAGE_RINGTONE:
253 case AudioStandard::STREAM_USAGE_VOICE_RINGTONE:
254 case AudioStandard::STREAM_USAGE_NOTIFICATION:
255 case AudioStandard::STREAM_USAGE_ACCESSIBILITY:
256 case AudioStandard::STREAM_USAGE_SYSTEM:
257 case AudioStandard::STREAM_USAGE_MOVIE:
258 case AudioStandard::STREAM_USAGE_GAME:
259 case AudioStandard::STREAM_USAGE_AUDIOBOOK:
260 case AudioStandard::STREAM_USAGE_NAVIGATION:
261 case AudioStandard::STREAM_USAGE_DTMF:
262 case AudioStandard::STREAM_USAGE_ENFORCED_TONE:
263 return true;
264 default:
265 break;
266 }
267 MEDIA_LOGE("CheckAudioStreamUsage: streamUsage %{public}d is invalid", streamUsage);
268 return false;
269 }
270
SetStreamUsage(const int32_t & sourceID,const AudioStandard::StreamUsage & streamUsage)271 int32_t AudioHapticManagerImpl::SetStreamUsage(const int32_t &sourceID, const AudioStandard::StreamUsage &streamUsage)
272 {
273 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
274 if (audioHapticPlayerMap_.count(sourceID) == 0 || audioHapticPlayerMap_[sourceID] == nullptr) {
275 MEDIA_LOGE("SetStreamUsage: failed for invalid sourceID: %{public}d", sourceID);
276 return MSERR_INVALID_VAL;
277 }
278 if (!CheckAudioStreamUsage(streamUsage)) {
279 MEDIA_LOGE("SetStreamUsage: failed for invalid latencyMode: %{public}d", streamUsage);
280 return MSERR_INVALID_VAL;
281 }
282 audioHapticPlayerMap_[sourceID]->streamUsage_ = streamUsage;
283 return MSERR_OK;
284 }
285
CreatePlayer(const int32_t & sourceID,const AudioHapticPlayerOptions & audioHapticPlayerOptions)286 std::shared_ptr<AudioHapticPlayer> AudioHapticManagerImpl::CreatePlayer(const int32_t &sourceID,
287 const AudioHapticPlayerOptions &audioHapticPlayerOptions)
288 {
289 std::lock_guard<std::mutex> lock(audioHapticManagerMutex_);
290 if (audioHapticPlayerMap_.count(sourceID) == 0 || audioHapticPlayerMap_[sourceID] == nullptr) {
291 MEDIA_LOGE("CreatePlayer failed for sourceID: %{public}d", sourceID);
292 return nullptr;
293 }
294
295 std::shared_ptr<AudioHapticPlayerInfo> audioHapticPlayerInfo = audioHapticPlayerMap_[sourceID];
296 AudioHapticPlayerParam param = AudioHapticPlayerParam(audioHapticPlayerOptions,
297 audioHapticPlayerInfo->audioSource_, audioHapticPlayerInfo->hapticSource_,
298 audioHapticPlayerInfo->latencyMode_, audioHapticPlayerInfo->streamUsage_);
299 std::shared_ptr<AudioHapticPlayer> audioHapticPlayer = AudioHapticPlayerFactory::CreateAudioHapticPlayer(param);
300
301 if (audioHapticPlayer == nullptr) {
302 MEDIA_LOGE("CreatePlayer failed for sourceID: %{public}d", sourceID);
303 return nullptr;
304 }
305 return audioHapticPlayer;
306 }
307
ReleasePlayerInfo(const std::shared_ptr<AudioHapticPlayerInfo> & info)308 void AudioHapticManagerImpl::ReleasePlayerInfo(const std::shared_ptr<AudioHapticPlayerInfo>& info)
309 {
310 if (info == nullptr) {
311 return;
312 }
313
314 auto audioSrc = info->audioSource_;
315 if (!audioSrc.audioUri.empty()) {
316 int32_t fd = ExtractFd(audioSrc.audioUri);
317 if (fd > FILE_DESCRIPTOR_INVALID) {
318 close(fd);
319 }
320 }
321 int32_t audioFd = audioSrc.fd;
322 if (audioFd > FILE_DESCRIPTOR_INVALID) {
323 close(audioFd);
324 }
325
326 auto hapticSrc = info->hapticSource_;
327 if (!hapticSrc.hapticUri.empty()) {
328 int32_t fd = ExtractFd(hapticSrc.hapticUri);
329 if (fd > FILE_DESCRIPTOR_INVALID) {
330 close(fd);
331 }
332 }
333 int32_t hapticFd = hapticSrc.fd;
334 if (hapticFd > FILE_DESCRIPTOR_INVALID) {
335 close(hapticFd);
336 }
337 }
338 } // namesapce AudioStandard
339 } // namespace OHOS
340