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 static const int32_t ERROR_RETURN = -1;
28 }
29
30 namespace OHOS {
31 namespace Media {
CreateSoundPool(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)32 std::shared_ptr<ISoundPool> SoundPoolFactory::CreateSoundPool(int maxStreams,
33 AudioStandard::AudioRendererInfo audioRenderInfo)
34 {
35 MEDIA_LOGI("SoundPoolFactory::CreateSoundPool");
36 std::shared_ptr<SoundPool> impl;
37 if (!SoundPool::CheckInitParam(maxStreams, audioRenderInfo)) {
38 return nullptr;
39 }
40 int32_t apiVersion = GetAPIVersion();
41 CHECK_AND_RETURN_RET_LOG(apiVersion > 0 || apiVersion == FAULT_API_VERSION, nullptr, "invalid apiVersion");
42 if (apiVersion > 0 && apiVersion < SOUNDPOOL_API_VERSION_ISOLATION) {
43 MEDIA_LOGI("SoundPoolFactory::CreateSoundPool go old version");
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
CreateParallelSoundPool(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)64 std::shared_ptr<ISoundPool> SoundPoolFactory::CreateParallelSoundPool(int maxStreams,
65 AudioStandard::AudioRendererInfo audioRenderInfo)
66 {
67 MEDIA_LOGI("SoundPoolFactory::CreateParallelSoundPool");
68 std::shared_ptr<SoundPool> impl;
69 if (!SoundPool::CheckInitParam(maxStreams, audioRenderInfo)) {
70 return nullptr;
71 }
72 int32_t apiVersion = GetAPIVersion();
73 CHECK_AND_RETURN_RET_LOG(apiVersion > 0 || apiVersion == FAULT_API_VERSION, nullptr, "invalid apiVersion");
74 int32_t ret = SoundPoolManagerMulti::GetInstance().GetSoundPoolInstance(impl);
75 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK && impl != nullptr, nullptr, "failed to get SoundPoolMulti");
76
77 ret = impl->InitParallel(maxStreams, audioRenderInfo);
78 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, nullptr, "failed to init SoundPoolMulti");
79 impl->SetApiVersion(apiVersion);
80
81 return impl;
82 }
83
SoundPool()84 SoundPool::SoundPool()
85 {
86 MEDIA_LOGI("Construction SoundPool.");
87 }
88
~SoundPool()89 SoundPool::~SoundPool()
90 {
91 MEDIA_LOGI("Destruction SoundPool.");
92 ReleaseInner();
93 }
94
Init(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)95 int32_t SoundPool::Init(int maxStreams, AudioStandard::AudioRendererInfo audioRenderInfo)
96 {
97 // start contruct stream manager
98 std::lock_guard lock(soundPoolLock_);
99 streamIdManager_ = std::make_shared<StreamIDManager>(maxStreams, audioRenderInfo);
100 int ret = streamIdManager_->InitThreadPool();
101 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_VAL, "failed to init streamIdManager");
102 soundIDManager_ = std::make_shared<SoundIDManager>();
103 return MSERR_OK;
104 }
105
InitParallel(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)106 int32_t SoundPool::InitParallel(int maxStreams, AudioStandard::AudioRendererInfo audioRenderInfo)
107 {
108 std::lock_guard lock(soundPoolLock_);
109 soundIDManager_ = std::make_shared<SoundIDManager>();
110 parallelStreamManager_ = std::make_shared<ParallelStreamManager>(maxStreams, audioRenderInfo);
111 int ret = parallelStreamManager_->InitThreadPool();
112 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_VAL, "failed to init parallelStreamManager");
113 parallelStreamFlag_ = true;
114 return MSERR_OK;
115 }
116
CheckInitParam(int maxStreams,AudioStandard::AudioRendererInfo audioRenderInfo)117 bool SoundPool::CheckInitParam(int maxStreams, AudioStandard::AudioRendererInfo audioRenderInfo)
118 {
119 if (maxStreams <= 0) {
120 return false;
121 }
122 bool isRendererFlagsInvalid = !CheckRendererFlagsValid(audioRenderInfo);
123 if (audioRenderInfo.contentType < AudioStandard::CONTENT_TYPE_UNKNOWN
124 || audioRenderInfo.contentType > AudioStandard::CONTENT_TYPE_ULTRASONIC
125 || audioRenderInfo.streamUsage < AudioStandard::STREAM_USAGE_UNKNOWN
126 || audioRenderInfo.streamUsage > AudioStandard::STREAM_USAGE_VOICE_MODEM_COMMUNICATION
127 || isRendererFlagsInvalid) {
128 return false;
129 }
130 return true;
131 }
132
Load(const std::string url)133 int32_t SoundPool::Load(const std::string url)
134 {
135 MediaTrace trace("SoundPool::Load url");
136 std::lock_guard lock(soundPoolLock_);
137 MEDIA_LOGI("SoundPool::Load url::%{public}s", url.c_str());
138 CHECK_AND_RETURN_RET_LOG(!url.empty(), -1, "Failed to obtain SoundPool for load");
139 CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
140 return soundIDManager_->Load(url, apiVersion_);
141 }
142
Load(int32_t fd,int64_t offset,int64_t length)143 int32_t SoundPool::Load(int32_t fd, int64_t offset, int64_t length)
144 {
145 MediaTrace trace("SoundPool::Load fd");
146 std::lock_guard lock(soundPoolLock_);
147 MEDIA_LOGI("SoundPool::Load fd::%{public}d, offset::%{public}s, length::%{public}s", fd,
148 std::to_string(offset).c_str(), std::to_string(length).c_str());
149 CHECK_AND_RETURN_RET_LOG((fd > 0 && length > 0 && offset >= 0), -1, "Invalid fd param.");
150 CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
151 return soundIDManager_->Load(fd, offset, length, apiVersion_);
152 }
153
Play(int32_t soundID,PlayParams playParameters)154 int32_t SoundPool::Play(int32_t soundID, PlayParams playParameters)
155 {
156 MediaTrace trace("SoundPool::Play");
157 std::lock_guard lock(soundPoolLock_);
158 MEDIA_LOGI("SoundPool::Play soundID::%{public}d ,priority::%{public}d", soundID, playParameters.priority);
159 CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
160 std::shared_ptr<SoundParser> soundParser = soundIDManager_->FindSoundParser(soundID);
161
162 CHECK_AND_RETURN_RET_LOG(soundParser != nullptr, -1, "Invalid sound.");
163 if (!soundParser->IsSoundParserCompleted()) {
164 MEDIA_LOGE("sound load no completed. ");
165 return -1;
166 }
167 int32_t streamID;
168 if (parallelStreamFlag_) {
169 CHECK_AND_RETURN_RET_LOG(parallelStreamManager_ != nullptr, ERROR_RETURN,
170 "parallelStreamManager_ have released.");
171 streamID = parallelStreamManager_->Play(soundParser, playParameters);
172 } else {
173 CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, ERROR_RETURN, "sound pool have released.");
174 streamID = streamIdManager_->Play(soundParser, playParameters);
175 }
176 MEDIA_LOGI("SoundPool::Play streamID::%{public}d", streamID);
177 return streamID;
178 }
179
Stop(int32_t streamID)180 int32_t SoundPool::Stop(int32_t streamID)
181 {
182 MediaTrace trace("SoundPool::Stop");
183 std::lock_guard lock(soundPoolLock_);
184 MEDIA_LOGI("SoundPool::Stop streamID::%{public}d", streamID);
185 if (parallelStreamFlag_) {
186 CHECK_AND_RETURN_RET_LOG(parallelStreamManager_ != nullptr, MSERR_INVALID_VAL,
187 "parallelStreamManager_ have released.");
188 if (std::shared_ptr<Stream> stream = parallelStreamManager_->FindStreamLock(streamID)) {
189 return stream->Stop();
190 }
191 } else {
192 CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
193 if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBufferLock(streamID)) {
194 return cacheBuffer->Stop(streamID);
195 }
196 }
197 MEDIA_LOGI("SoundPool::Stop can not find stream or cachebuffer streamID::%{public}d", streamID);
198 return MSERR_INVALID_OPERATION;
199 }
200
SetLoop(int32_t streamID,int32_t loop)201 int32_t SoundPool::SetLoop(int32_t streamID, int32_t loop)
202 {
203 std::lock_guard lock(soundPoolLock_);
204 MEDIA_LOGI("SoundPool::SetLoop streamID:%{public}d, loop:%{public}d", streamID, loop);
205 if (parallelStreamFlag_) {
206 CHECK_AND_RETURN_RET_LOG(parallelStreamManager_ != nullptr, MSERR_INVALID_VAL,
207 "parallelStreamManager_ have released.");
208 if (std::shared_ptr<Stream> stream = parallelStreamManager_->FindStreamLock(streamID)) {
209 return stream->SetLoop(loop);
210 }
211 } else {
212 CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
213 if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBufferLock(streamID)) {
214 return cacheBuffer->SetLoop(streamID, loop);
215 }
216 }
217 MEDIA_LOGI("SoundPool::SetLoop can not find stream or cachebuffer streamID::%{public}d", streamID);
218 return MSERR_INVALID_OPERATION;
219 }
220
SetPriority(int32_t streamID,int32_t priority)221 int32_t SoundPool::SetPriority(int32_t streamID, int32_t priority)
222 {
223 std::lock_guard lock(soundPoolLock_);
224 MEDIA_LOGI("SoundPool::SetPriority streamID::%{public}d ,priority::%{public}d", streamID, priority);
225 if (priority < MIN_STREAM_PRIORITY) {
226 MEDIA_LOGI("Invalid priority, align priority to min.");
227 priority = MIN_STREAM_PRIORITY;
228 }
229 if (parallelStreamFlag_) {
230 CHECK_AND_RETURN_RET_LOG(parallelStreamManager_ != nullptr, MSERR_INVALID_VAL,
231 "parallelStreamManager_ have released.");
232 if (std::shared_ptr<Stream> stream = parallelStreamManager_->FindStreamLock(streamID)) {
233 int32_t ret = stream->SetPriority(priority);
234 parallelStreamManager_->ReorderStream();
235 return ret;
236 }
237 } else {
238 CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
239 if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBufferLock(streamID)) {
240 int32_t ret = cacheBuffer->SetPriority(streamID, priority);
241 streamIdManager_->ReorderStream(streamID, priority);
242 return ret;
243 }
244 }
245 MEDIA_LOGI("SoundPool::SetPriority can not find stream or cachebuffer streamID::%{public}d", streamID);
246 return MSERR_INVALID_OPERATION;
247 }
248
SetRate(int32_t streamID,AudioStandard::AudioRendererRate renderRate)249 int32_t SoundPool::SetRate(int32_t streamID, AudioStandard::AudioRendererRate renderRate)
250 {
251 std::lock_guard lock(soundPoolLock_);
252 MEDIA_LOGI("SoundPool::SetRate streamID:%{public}d, renderRate:%{public}d", streamID, renderRate);
253 if (parallelStreamFlag_) {
254 CHECK_AND_RETURN_RET_LOG(parallelStreamManager_ != nullptr, MSERR_INVALID_VAL,
255 "parallelStreamManager_ have released.");
256 if (std::shared_ptr<Stream> stream = parallelStreamManager_->FindStreamLock(streamID)) {
257 return stream->SetRate(renderRate);
258 }
259 } else {
260 CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
261 if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBufferLock(streamID)) {
262 return cacheBuffer->SetRate(streamID, renderRate);
263 }
264 }
265 MEDIA_LOGI("SoundPool::SetRate can not find stream or cachebuffer streamID::%{public}d", streamID);
266 return MSERR_INVALID_OPERATION;
267 }
268
SetVolume(int32_t streamID,float leftVolume,float rightVolume)269 int32_t SoundPool::SetVolume(int32_t streamID, float leftVolume, float rightVolume)
270 {
271 if (!CheckVolumeVaild(&leftVolume, &rightVolume)) {
272 return MSERR_INVALID_VAL;
273 }
274 MEDIA_LOGI("SoundPool::SetVolume streamID:%{public}d, leftVolume:%{public}f, rightVolume:%{public}f",
275 streamID, leftVolume, rightVolume);
276 std::lock_guard lock(soundPoolLock_);
277 if (parallelStreamFlag_) {
278 CHECK_AND_RETURN_RET_LOG(parallelStreamManager_ != nullptr, MSERR_INVALID_VAL,
279 "parallelStreamManager_ have released.");
280 if (std::shared_ptr<Stream> stream = parallelStreamManager_->FindStreamLock(streamID)) {
281 return stream->SetVolume(leftVolume, rightVolume);
282 }
283 } else {
284 CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
285 if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBufferLock(streamID)) {
286 return cacheBuffer->SetVolume(streamID, leftVolume, rightVolume);
287 }
288 }
289 MEDIA_LOGI("SoundPool::SetVolume can not find stream or cachebuffer streamID::%{public}d", streamID);
290 return MSERR_INVALID_OPERATION;
291 }
292
Unload(int32_t soundID)293 int32_t SoundPool::Unload(int32_t soundID)
294 {
295 MediaTrace trace("SoundPool::Unload");
296 std::lock_guard lock(soundPoolLock_);
297 MEDIA_LOGI("SoundPool::Unload soundID::%{public}d", soundID);
298 CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
299 if (parallelStreamFlag_) {
300 CHECK_AND_RETURN_RET_LOG(parallelStreamManager_ != nullptr, MSERR_INVALID_VAL,
301 "parallelStreamManager_ have released.");
302 parallelStreamManager_->UnloadStream(soundID);
303 } else {
304 CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
305 int32_t streamID = streamIdManager_->GetStreamIDBySoundID(soundID);
306 if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBufferLock(streamID)) {
307 cacheBuffer->Stop(streamID);
308 cacheBuffer->Release();
309 streamIdManager_->ClearStreamIDInDeque(streamID, soundID);
310 }
311 }
312 return soundIDManager_->Unload(soundID);
313 }
314
Release()315 int32_t SoundPool::Release()
316 {
317 MEDIA_LOGI("SoundPool::Release");
318 return ReleaseInner();
319 }
320
ReleaseInner()321 int32_t SoundPool::ReleaseInner()
322 {
323 MediaTrace trace("SoundPool::ReleaseInner");
324 std::lock_guard lock(soundPoolLock_);
325 MEDIA_LOGI("SoundPool::ReleaseInner");
326 if (streamIdManager_ != nullptr) {
327 streamIdManager_.reset();
328 }
329 if (soundIDManager_ != nullptr) {
330 soundIDManager_.reset();
331 }
332 if (parallelStreamManager_ != nullptr) {
333 parallelStreamManager_.reset();
334 }
335 if (callback_ != nullptr) {
336 callback_.reset();
337 }
338 if (frameWriteCallback_ != nullptr) {
339 frameWriteCallback_.reset();
340 }
341
342 if (apiVersion_ > 0 && apiVersion_ < SOUNDPOOL_API_VERSION_ISOLATION && !parallelStreamFlag_ &&
343 !isReleased_) {
344 SoundPoolManager::GetInstance().Release(getpid());
345 isReleased_ = true;
346 MEDIA_LOGI("SoundPool::ReleaseInner old have released once");
347 } else if (apiVersion_ == FAULT_API_VERSION || apiVersion_ >= SOUNDPOOL_API_VERSION_ISOLATION ||
348 parallelStreamFlag_) {
349 std::shared_ptr<SoundPool> sharedPtr(this, [](SoundPool*) {
350 });
351 SoundPoolManagerMulti::GetInstance().ReleaseInstance(sharedPtr);
352 } else {
353 MEDIA_LOGI("SoundPool::ReleaseInner error apiVersion_: %{public}d", apiVersion_);
354 }
355 return MSERR_OK;
356 }
357
SetSoundPoolCallback(const std::shared_ptr<ISoundPoolCallback> & soundPoolCallback)358 int32_t SoundPool::SetSoundPoolCallback(const std::shared_ptr<ISoundPoolCallback> &soundPoolCallback)
359 {
360 MEDIA_LOGI("SoundPool::SetSoundPoolCallback");
361 if (soundIDManager_ != nullptr) {
362 soundIDManager_->SetCallback(soundPoolCallback);
363 }
364 if (streamIdManager_ != nullptr) {
365 streamIdManager_->SetCallback(soundPoolCallback);
366 }
367 if (parallelStreamManager_ != nullptr) {
368 parallelStreamManager_->SetCallback(soundPoolCallback);
369 }
370 callback_ = soundPoolCallback;
371 return MSERR_OK;
372 }
373
SetSoundPoolFrameWriteCallback(const std::shared_ptr<ISoundPoolFrameWriteCallback> & frameWriteCallback)374 int32_t SoundPool::SetSoundPoolFrameWriteCallback(
375 const std::shared_ptr<ISoundPoolFrameWriteCallback> &frameWriteCallback)
376 {
377 MEDIA_LOGI("SoundPool::SetSoundPoolFrameWriteCallback");
378 if (streamIdManager_ != nullptr) {
379 streamIdManager_->SetFrameWriteCallback(frameWriteCallback);
380 }
381 if (parallelStreamManager_ != nullptr) {
382 parallelStreamManager_->SetFrameWriteCallback(frameWriteCallback);
383 }
384 frameWriteCallback_ = frameWriteCallback;
385 return MSERR_OK;
386 }
387
CheckVolumeVaild(float * leftVol,float * rightVol)388 bool SoundPool::CheckVolumeVaild(float *leftVol, float *rightVol)
389 {
390 if (*leftVol != std::clamp(*leftVol, 0.f, 1.f) ||
391 *rightVol != std::clamp(*rightVol, 0.f, 1.f)) {
392 MEDIA_LOGI("volume l=%{public}f r=%{public}f out of (0.f, 1.f) bounds, using 1.f", *leftVol, *rightVol);
393 *leftVol = *rightVol = 1.f;
394 }
395 if (*leftVol != *rightVol) {
396 MEDIA_LOGI("left volume %{public}f set not eq the right volume %{public}f ,use the left volume",
397 *leftVol, *rightVol);
398 *rightVol = *leftVol;
399 }
400 return true;
401 }
402
SetApiVersion(int32_t apiVersion)403 void SoundPool::SetApiVersion(int32_t apiVersion)
404 {
405 std::lock_guard lock(soundPoolLock_);
406 apiVersion_ = apiVersion;
407 }
408
CheckRendererFlagsValid(AudioStandard::AudioRendererInfo audioRenderInfo)409 bool SoundPool::CheckRendererFlagsValid(AudioStandard::AudioRendererInfo audioRenderInfo)
410 {
411 if (audioRenderInfo.rendererFlags == 0 || audioRenderInfo.rendererFlags == 1) {
412 return true;
413 }
414 bool isBundleNameValid = false;
415 std::string bundleName = AudioStandard::AudioSystemManager::GetInstance()->GetSelfBundleName(getuid());
416 AudioStandard::AudioSystemManager::GetInstance()->CheckVKBInfo(bundleName, isBundleNameValid);
417 if (audioRenderInfo.rendererFlags == AudioStandard::AUDIO_FLAG_VKB_NORMAL && isBundleNameValid) {
418 return true;
419 }
420 if (audioRenderInfo.rendererFlags == AudioStandard::AUDIO_FLAG_VKB_FAST && isBundleNameValid) {
421 return true;
422 }
423 return false;
424 }
425
426 } // namespace Media
427 } // namespace OHOS
428