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 <unistd.h>
17 #include "media_errors.h"
18 #include "media_log.h"
19 #include "soundpool_manager.h"
20 #include "soundpool.h"
21 
22 namespace {
23     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SOUNDPOOL, "SoundPool"};
24 }
25 
26 namespace OHOS {
27 namespace Media {
CreateSoundPool(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)28 std::shared_ptr<ISoundPool> SoundPoolFactory::CreateSoundPool(int maxStreams,
29     AudioStandard::AudioRendererInfo audioRenderInfo)
30 {
31     MEDIA_LOGI("SoundPoolFactory::CreateSoundPool");
32     std::shared_ptr<SoundPool> impl;
33     if (!SoundPool::CheckInitParam(maxStreams, audioRenderInfo)) {
34         return nullptr;
35     }
36     SoundPoolManager::GetInstance().SetSoundPool(getpid(), impl);
37     SoundPoolManager::GetInstance().GetSoundPool(getpid(), impl);
38     CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr, "failed to get SoundPool");
39 
40     int32_t ret = impl->Init(maxStreams, audioRenderInfo);
41     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, nullptr, "failed to init SoundPool");
42 
43     return impl;
44 }
45 
SoundPool()46 SoundPool::SoundPool()
47 {
48     MEDIA_LOGI("Construction SoundPool.");
49 }
50 
~SoundPool()51 SoundPool::~SoundPool()
52 {
53     MEDIA_LOGI("Destruction SoundPool.");
54     ReleaseInner();
55 }
56 
Init(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)57 int32_t SoundPool::Init(int maxStreams, AudioStandard::AudioRendererInfo audioRenderInfo)
58 {
59     // start contruct stream manager
60     std::lock_guard lock(soundPoolLock_);
61     streamIdManager_ = std::make_shared<StreamIDManager>(maxStreams, audioRenderInfo);
62     soundIDManager_ = std::make_shared<SoundIDManager>();
63     return MSERR_OK;
64 }
65 
CheckInitParam(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)66 bool SoundPool::CheckInitParam(int maxStreams, AudioStandard::AudioRendererInfo audioRenderInfo)
67 {
68     if (maxStreams <= 0) {
69         return false;
70     }
71     if (audioRenderInfo.contentType < AudioStandard::CONTENT_TYPE_UNKNOWN
72         || audioRenderInfo.contentType > AudioStandard::CONTENT_TYPE_ULTRASONIC
73         || audioRenderInfo.streamUsage < AudioStandard::STREAM_USAGE_UNKNOWN
74         || audioRenderInfo.streamUsage > AudioStandard::STREAM_USAGE_VOICE_MODEM_COMMUNICATION
75         || audioRenderInfo.rendererFlags < 0 || audioRenderInfo.rendererFlags > 1) {
76         return false;
77     }
78     return true;
79 }
80 
Load(const std::string url)81 int32_t SoundPool::Load(const std::string url)
82 {
83     MediaTrace trace("SoundPool::Load url");
84     std::lock_guard lock(soundPoolLock_);
85     MEDIA_LOGI("SoundPool::Load url::%{public}s", url.c_str());
86     CHECK_AND_RETURN_RET_LOG(!url.empty(), -1, "Failed to obtain SoundPool for load");
87     CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
88     return soundIDManager_->Load(url);
89 }
90 
Load(int32_t fd,int64_t offset,int64_t length)91 int32_t SoundPool::Load(int32_t fd, int64_t offset, int64_t length)
92 {
93     MediaTrace trace("SoundPool::Load fd");
94     std::lock_guard lock(soundPoolLock_);
95     MEDIA_LOGI("SoundPool::Load fd::%{public}d, offset::%{public}s, length::%{public}s", fd,
96         std::to_string(offset).c_str(), std::to_string(length).c_str());
97     CHECK_AND_RETURN_RET_LOG((fd > 0 && length > 0 && offset >= 0), -1, "Invalid fd param.");
98     CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
99     return soundIDManager_->Load(fd, offset, length);
100 }
101 
Play(int32_t soundID,PlayParams playParameters)102 int32_t SoundPool::Play(int32_t soundID, PlayParams playParameters)
103 {
104     MediaTrace trace("SoundPool::Play");
105     std::lock_guard lock(soundPoolLock_);
106     MEDIA_LOGI("SoundPool::Play soundID::%{public}d ,priority::%{public}d", soundID, playParameters.priority);
107     CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, -1, "sound pool have released.");
108     CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
109     std::shared_ptr<SoundParser> soundParser = soundIDManager_->FindSoundParser(soundID);
110 
111     CHECK_AND_RETURN_RET_LOG(soundParser != nullptr, -1, "Invalid sound.");
112     if (!soundParser->IsSoundParserCompleted()) {
113         MEDIA_LOGE("sound load no completed. ");
114         return -1;
115     }
116     const int32_t streamID = streamIdManager_->Play(soundParser, playParameters);
117     MEDIA_LOGI("SoundPool::Play streamID::%{public}d", streamID);
118     return streamID;
119 }
120 
Stop(int32_t streamID)121 int32_t SoundPool::Stop(int32_t streamID)
122 {
123     MediaTrace trace("SoundPool::Stop");
124     std::lock_guard lock(soundPoolLock_);
125     MEDIA_LOGI("SoundPool::Stop streamID::%{public}d", streamID);
126     CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
127     if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
128         return cacheBuffer->Stop(streamID);
129     }
130     return MSERR_INVALID_OPERATION;
131 }
132 
SetLoop(int32_t streamID,int32_t loop)133 int32_t SoundPool::SetLoop(int32_t streamID, int32_t loop)
134 {
135     std::lock_guard lock(soundPoolLock_);
136     MEDIA_LOGI("SoundPool::SetLoop streamID:%{public}d, loop:%{public}d", streamID, loop);
137     CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
138     if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
139         return cacheBuffer->SetLoop(streamID, loop);
140     }
141     return MSERR_INVALID_OPERATION;
142 }
143 
SetPriority(int32_t streamID,int32_t priority)144 int32_t SoundPool::SetPriority(int32_t streamID, int32_t priority)
145 {
146     std::lock_guard lock(soundPoolLock_);
147     MEDIA_LOGI("SoundPool::SetPriority streamID::%{public}d ,priority::%{public}d", streamID, priority);
148     CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
149     if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
150         if (priority < MIN_STREAM_PRIORITY) {
151             MEDIA_LOGI("Invalid priority, align priority to min.");
152             priority = MIN_STREAM_PRIORITY;
153         }
154         int32_t ret = cacheBuffer->SetPriority(streamID, priority);
155         streamIdManager_->ReorderStream(streamID, priority);
156         return ret;
157     }
158     return MSERR_INVALID_OPERATION;
159 }
160 
SetRate(int32_t streamID,AudioStandard::AudioRendererRate renderRate)161 int32_t SoundPool::SetRate(int32_t streamID, AudioStandard::AudioRendererRate renderRate)
162 {
163     std::lock_guard lock(soundPoolLock_);
164     MEDIA_LOGI("SoundPool::SetRate streamID:%{public}d, renderRate:%{public}d", streamID, renderRate);
165     CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
166     if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
167         return cacheBuffer->SetRate(streamID, renderRate);
168     }
169     return MSERR_INVALID_OPERATION;
170 }
171 
SetVolume(int32_t streamID,float leftVolume,float rightVolume)172 int32_t SoundPool::SetVolume(int32_t streamID, float leftVolume, float rightVolume)
173 {
174     if (!CheckVolumeVaild(&leftVolume, &rightVolume)) {
175         return MSERR_INVALID_VAL;
176     }
177     MEDIA_LOGI("SoundPool::SetVolume streamID:%{public}d, leftVolume:%{public}f, rightVolume:%{public}f",
178         streamID, leftVolume, rightVolume);
179     CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
180     std::lock_guard lock(soundPoolLock_);
181     if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
182         return cacheBuffer->SetVolume(streamID, leftVolume, rightVolume);
183     }
184     return MSERR_INVALID_OPERATION;
185 }
186 
Unload(int32_t soundID)187 int32_t SoundPool::Unload(int32_t soundID)
188 {
189     MediaTrace trace("SoundPool::Unload");
190     std::lock_guard lock(soundPoolLock_);
191     MEDIA_LOGI("SoundPool::Unload soundID::%{public}d", soundID);
192     CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, -1, "sound pool have released.");
193     CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
194     int32_t streamID = streamIdManager_->GetStreamIDBySoundID(soundID);
195     if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
196         cacheBuffer->Stop(streamID);
197         cacheBuffer->Release();
198         streamIdManager_->ClearStreamIDInDeque(streamID);
199     }
200     return soundIDManager_->Unload(soundID);
201 }
202 
Release()203 int32_t SoundPool::Release()
204 {
205     MEDIA_LOGI("SoundPool::Release");
206     return ReleaseInner();
207 }
208 
ReleaseInner()209 int32_t SoundPool::ReleaseInner()
210 {
211     MediaTrace trace("SoundPool::ReleaseInner");
212     std::lock_guard lock(soundPoolLock_);
213     MEDIA_LOGI("SoundPool::ReleaseInner");
214     if (streamIdManager_ != nullptr) {
215         streamIdManager_.reset();
216     }
217     if (soundIDManager_ != nullptr) {
218         soundIDManager_.reset();
219     }
220     if (callback_ != nullptr) {
221         callback_.reset();
222     }
223     if (frameWriteCallback_ != nullptr) {
224         frameWriteCallback_.reset();
225     }
226     SoundPoolManager::GetInstance().Release(getpid());
227     return MSERR_OK;
228 }
229 
SetSoundPoolCallback(const std::shared_ptr<ISoundPoolCallback> & soundPoolCallback)230 int32_t SoundPool::SetSoundPoolCallback(const std::shared_ptr<ISoundPoolCallback> &soundPoolCallback)
231 {
232     MEDIA_LOGI("SoundPool::SetSoundPoolCallback");
233     if (soundIDManager_ != nullptr) soundIDManager_->SetCallback(soundPoolCallback);
234     if (streamIdManager_ != nullptr) streamIdManager_->SetCallback(soundPoolCallback);
235     callback_ = soundPoolCallback;
236     return MSERR_OK;
237 }
238 
SetSoundPoolFrameWriteCallback(const std::shared_ptr<ISoundPoolFrameWriteCallback> & frameWriteCallback)239 int32_t SoundPool::SetSoundPoolFrameWriteCallback(
240     const std::shared_ptr<ISoundPoolFrameWriteCallback> &frameWriteCallback)
241 {
242     MEDIA_LOGI("SoundPool::SetSoundPoolFrameWriteCallback");
243     if (streamIdManager_ != nullptr) streamIdManager_->SetFrameWriteCallback(frameWriteCallback);
244     frameWriteCallback_ = frameWriteCallback;
245     return MSERR_OK;
246 }
247 
CheckVolumeVaild(float * leftVol,float * rightVol)248 bool SoundPool::CheckVolumeVaild(float *leftVol, float *rightVol)
249 {
250     if (*leftVol != std::clamp(*leftVol, 0.f, 1.f) ||
251         *rightVol != std::clamp(*rightVol, 0.f, 1.f)) {
252         MEDIA_LOGI("volume l=%{public}f r=%{public}f out of (0.f, 1.f) bounds, using 1.f", *leftVol, *rightVol);
253         *leftVol = *rightVol = 1.f;
254     }
255     if (*leftVol != *rightVol) {
256         MEDIA_LOGI("left volume %{public}f set not eq the right volume %{public}f ,use the left volume",
257             *leftVol, *rightVol);
258         *rightVol = *leftVol;
259     }
260     return true;
261 }
262 } // namespace Media
263 } // namespace OHOS
264