• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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