• 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 #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