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