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 "media_log.h"
17 #include "media_errors.h"
18 #include "parameter.h"
19 #include "string_ex.h"
20 #include "sound_id_manager.h"
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SOUNDPOOL, "SoundIDManager"};
24 static const std::string THREAD_POOL_NAME = "OS_SoundMgr";
25 static const int32_t MAX_THREADS_NUM = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
26 static constexpr size_t MAX_LOAD_NUM = 32;
27 static constexpr size_t MAX_LOAD_NUM_API16 = 128;
28 static const int32_t SOUNDPOOL_API_VERSION_ISOLATION = 18;
29 static const int32_t FAULT_API_VERSION = -1;
30 }
31
32 namespace OHOS {
33 namespace Media {
SoundIDManager()34 SoundIDManager::SoundIDManager() : isParsingThreadPoolStarted_(false), quitQueue_(false)
35 {
36 MEDIA_LOGI("Construction SoundIDManager");
37 InitThreadPool();
38 }
39
~SoundIDManager()40 SoundIDManager::~SoundIDManager()
41 {
42 MEDIA_LOGI("Destruction SoundIDManager");
43 {
44 std::lock_guard lock(soundManagerLock_);
45 quitQueue_ = true;
46 queueSpaceValid_.notify_all(); // notify all load waiters
47 queueDataValid_.notify_all(); // notify all worker threads
48 }
49
50 if (callback_ != nullptr) {
51 callback_.reset();
52 }
53 {
54 std::lock_guard lock(soundManagerLock_);
55 for (auto soundParser : soundParsers_) {
56 if (soundParser.second != nullptr) {
57 soundParser.second->Release();
58 }
59 }
60 soundParsers_.clear();
61 }
62
63 if (isParsingThreadPoolStarted_) {
64 if (soundParserThreadPool_ != nullptr) {
65 soundParserThreadPool_->Stop();
66 }
67 isParsingThreadPoolStarted_ = false;
68 }
69 }
70
InitThreadPool()71 int32_t SoundIDManager::InitThreadPool()
72 {
73 if (isParsingThreadPoolStarted_) {
74 return MSERR_OK;
75 }
76 soundParserThreadPool_ = std::make_unique<ThreadPool>(THREAD_POOL_NAME);
77 CHECK_AND_RETURN_RET_LOG(soundParserThreadPool_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain ThreadPool");
78 soundParserThreadPool_->Start(MAX_THREADS_NUM);
79 isParsingThreadPoolStarted_ = true;
80
81 return MSERR_OK;
82 }
83
Load(std::string url,int32_t apiVersion)84 int32_t SoundIDManager::Load(std::string url, int32_t apiVersion)
85 {
86 int32_t soundID;
87 {
88 std::lock_guard lock(soundManagerLock_);
89 size_t soundParserNum = soundParsers_.size();
90 if (apiVersion > 0 && apiVersion < SOUNDPOOL_API_VERSION_ISOLATION) {
91 CHECK_AND_RETURN_RET_LOG(soundParserNum < MAX_LOAD_NUM, invalidSoundIDFlag,
92 "failed to create soundParser url soundParsers_ :%{public}zu", soundParserNum);
93 } else if (apiVersion == FAULT_API_VERSION || apiVersion >= SOUNDPOOL_API_VERSION_ISOLATION) {
94 CHECK_AND_RETURN_RET_LOG(soundParserNum < MAX_LOAD_NUM_API16, invalidSoundIDFlag,
95 "failed to create soundParser url api16 soundParsers_ :%{public}zu", soundParserNum);
96 }
97 const std::string fdHead = "fd://";
98 if (url.find(fdHead) == std::string::npos) {
99 return invalidSoundIDFlag;
100 }
101 int32_t fd = -1;
102 StrToInt(url.substr(fdHead.size()), fd);
103 if (fd < 0) {
104 return invalidSoundIDFlag;
105 }
106 do {
107 nextSoundID_ = nextSoundID_ == INT32_MAX ? 1 : nextSoundID_ + 1;
108 } while (FindSoundParser(nextSoundID_) != nullptr);
109 soundID = nextSoundID_;
110 auto soundParser = std::make_shared<SoundParser>(soundID, url);
111 CHECK_AND_RETURN_RET_LOG(soundParser != nullptr, -1, "failed to create soundParser");
112 soundParsers_.emplace(soundID, soundParser);
113 }
114 DoLoad(soundID);
115 return soundID;
116 }
117
Load(int32_t fd,int64_t offset,int64_t length,int32_t apiVersion)118 int32_t SoundIDManager::Load(int32_t fd, int64_t offset, int64_t length, int32_t apiVersion)
119 {
120 int32_t soundID;
121 {
122 std::lock_guard lock(soundManagerLock_);
123 size_t soundParserNum = soundParsers_.size();
124 if (apiVersion > 0 && apiVersion < SOUNDPOOL_API_VERSION_ISOLATION) {
125 CHECK_AND_RETURN_RET_LOG(soundParserNum < MAX_LOAD_NUM, invalidSoundIDFlag,
126 "failed to create soundParser fd soundParsers_ :%{public}zu", soundParserNum);
127 } else if (apiVersion == FAULT_API_VERSION || apiVersion >= SOUNDPOOL_API_VERSION_ISOLATION) {
128 CHECK_AND_RETURN_RET_LOG(soundParserNum < MAX_LOAD_NUM_API16, invalidSoundIDFlag,
129 "failed to create soundParser fd api16 soundParsers_ :%{public}zu", soundParserNum);
130 }
131 do {
132 nextSoundID_ = nextSoundID_ == INT32_MAX ? 1 : nextSoundID_ + 1;
133 } while (FindSoundParser(nextSoundID_) != nullptr);
134 soundID = nextSoundID_;
135 auto soundParser = std::make_shared<SoundParser>(soundID, fd, offset, length);
136 CHECK_AND_RETURN_RET_LOG(soundParser != nullptr, -1, "failed to create soundParser");
137 soundParsers_.emplace(soundID, soundParser);
138 }
139 DoLoad(soundID);
140 return soundID;
141 }
142
DoLoad(int32_t soundID)143 int32_t SoundIDManager::DoLoad(int32_t soundID)
144 {
145 MEDIA_LOGI("SoundIDManager::DoLoad soundID:%{public}d", soundID);
146 if (!isParsingThreadPoolStarted_) {
147 InitThreadPool();
148 }
149 {
150 std::unique_lock lock(soundManagerLock_);
151 while (soundIDs_.size() == MAX_SOUND_ID_QUEUE) {
152 if (quitQueue_) return MSERR_OK;
153 queueSpaceValid_.wait(lock);
154 }
155 if (quitQueue_) return MSERR_OK;
156 soundIDs_.push_back(soundID);
157 queueDataValid_.notify_one();
158 }
159 ThreadPool::Task soundParsingTask = [this] { this->DoParser(); };
160 CHECK_AND_RETURN_RET_LOG(soundParserThreadPool_ != nullptr, MSERR_INVALID_VAL, "Failed to obtain ThreadPool");
161 CHECK_AND_RETURN_RET_LOG(soundParsingTask != nullptr, MSERR_INVALID_VAL, "Failed to obtain Task");
162 soundParserThreadPool_->AddTask(soundParsingTask);
163 return MSERR_OK;
164 }
165
DoParser()166 int32_t SoundIDManager::DoParser()
167 {
168 std::unique_lock lock(soundManagerLock_);
169 while (!quitQueue_) {
170 if (soundIDs_.empty()) {
171 queueDataValid_.wait_for(
172 lock, std::chrono::duration<int32_t, std::milli>(WAIT_TIME_BEFORE_CLOSE_MS));
173 if (soundIDs_.empty()) {
174 // no new sound, exit this thread.
175 break;
176 }
177 continue;
178 }
179 const int32_t soundID = soundIDs_.front();
180 soundIDs_.pop_front();
181 queueSpaceValid_.notify_one();
182 std::shared_ptr<SoundParser> soundParser = FindSoundParser(soundID);
183 lock.unlock();
184 if (soundParser.get() != nullptr) {
185 soundParser->SetCallback(callback_);
186 soundParser->DoParser();
187 }
188 lock.lock();
189 }
190 return MSERR_OK;
191 }
192
193
FindSoundParser(int32_t soundID) const194 std::shared_ptr<SoundParser> SoundIDManager::FindSoundParser(int32_t soundID) const
195 {
196 MEDIA_LOGI("SoundIDManager::FindSoundParser soundID:%{public}d", soundID);
197 if (soundParsers_.empty()) {
198 return nullptr;
199 }
200 if (soundParsers_.find(soundID) != soundParsers_.end()) {
201 return soundParsers_.at(soundID);
202 }
203 return nullptr;
204 }
205
Unload(int32_t soundID)206 int32_t SoundIDManager::Unload(int32_t soundID)
207 {
208 MEDIA_LOGI("SoundIDManager::Unload soundID:%{public}d", soundID);
209 std::unique_lock lock(soundManagerLock_);
210 CHECK_AND_RETURN_RET_LOG(!soundParsers_.empty(), MSERR_NO_MEMORY, "No sound in the soundParsers_");
211 auto it = soundParsers_.find(soundID);
212 if (it != soundParsers_.end()) {
213 if (it->second != nullptr) {
214 it->second.reset();
215 }
216 soundParsers_.erase(it);
217 } else {
218 MEDIA_LOGI("Invalid soundID, unload failed");
219 return MSERR_INVALID_VAL;
220 }
221 return MSERR_OK;
222 }
223
SetCallback(const std::shared_ptr<ISoundPoolCallback> & callback)224 int32_t SoundIDManager::SetCallback(const std::shared_ptr<ISoundPoolCallback> &callback)
225 {
226 callback_ = callback;
227 return MSERR_OK;
228 }
229 } // namespace Media
230 } // namespace OHOS
231