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