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