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