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