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