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