1049e185fSopenharmony_ci/*
2049e185fSopenharmony_ci * Copyright (C) 2023 Huawei Device Co., Ltd.
3049e185fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4049e185fSopenharmony_ci * you may not use this file except in compliance with the License.
5049e185fSopenharmony_ci * You may obtain a copy of the License at
6049e185fSopenharmony_ci *
7049e185fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8049e185fSopenharmony_ci *
9049e185fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10049e185fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11049e185fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12049e185fSopenharmony_ci * See the License for the specific language governing permissions and
13049e185fSopenharmony_ci * limitations under the License.
14049e185fSopenharmony_ci */
15049e185fSopenharmony_ci
16049e185fSopenharmony_ci#include <unistd.h>
17049e185fSopenharmony_ci#include "media_errors.h"
18049e185fSopenharmony_ci#include "media_log.h"
19049e185fSopenharmony_ci#include "soundpool_manager.h"
20049e185fSopenharmony_ci#include "soundpool.h"
21049e185fSopenharmony_ci
22049e185fSopenharmony_cinamespace {
23049e185fSopenharmony_ci    constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_SOUNDPOOL, "SoundPool"};
24049e185fSopenharmony_ci}
25049e185fSopenharmony_ci
26049e185fSopenharmony_cinamespace OHOS {
27049e185fSopenharmony_cinamespace Media {
28049e185fSopenharmony_cistd::shared_ptr<ISoundPool> SoundPoolFactory::CreateSoundPool(int maxStreams,
29049e185fSopenharmony_ci    AudioStandard::AudioRendererInfo audioRenderInfo)
30049e185fSopenharmony_ci{
31049e185fSopenharmony_ci    MEDIA_LOGI("SoundPoolFactory::CreateSoundPool");
32049e185fSopenharmony_ci    std::shared_ptr<SoundPool> impl;
33049e185fSopenharmony_ci    if (!SoundPool::CheckInitParam(maxStreams, audioRenderInfo)) {
34049e185fSopenharmony_ci        return nullptr;
35049e185fSopenharmony_ci    }
36049e185fSopenharmony_ci    SoundPoolManager::GetInstance().SetSoundPool(getpid(), impl);
37049e185fSopenharmony_ci    SoundPoolManager::GetInstance().GetSoundPool(getpid(), impl);
38049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr, "failed to get SoundPool");
39049e185fSopenharmony_ci
40049e185fSopenharmony_ci    int32_t ret = impl->Init(maxStreams, audioRenderInfo);
41049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, nullptr, "failed to init SoundPool");
42049e185fSopenharmony_ci
43049e185fSopenharmony_ci    return impl;
44049e185fSopenharmony_ci}
45049e185fSopenharmony_ci
46049e185fSopenharmony_ciSoundPool::SoundPool()
47049e185fSopenharmony_ci{
48049e185fSopenharmony_ci    MEDIA_LOGI("Construction SoundPool.");
49049e185fSopenharmony_ci}
50049e185fSopenharmony_ci
51049e185fSopenharmony_ciSoundPool::~SoundPool()
52049e185fSopenharmony_ci{
53049e185fSopenharmony_ci    MEDIA_LOGI("Destruction SoundPool.");
54049e185fSopenharmony_ci    ReleaseInner();
55049e185fSopenharmony_ci}
56049e185fSopenharmony_ci
57049e185fSopenharmony_ciint32_t SoundPool::Init(int maxStreams, AudioStandard::AudioRendererInfo audioRenderInfo)
58049e185fSopenharmony_ci{
59049e185fSopenharmony_ci    // start contruct stream manager
60049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
61049e185fSopenharmony_ci    streamIdManager_ = std::make_shared<StreamIDManager>(maxStreams, audioRenderInfo);
62049e185fSopenharmony_ci    soundIDManager_ = std::make_shared<SoundIDManager>();
63049e185fSopenharmony_ci    return MSERR_OK;
64049e185fSopenharmony_ci}
65049e185fSopenharmony_ci
66049e185fSopenharmony_cibool SoundPool::CheckInitParam(int maxStreams, AudioStandard::AudioRendererInfo audioRenderInfo)
67049e185fSopenharmony_ci{
68049e185fSopenharmony_ci    if (maxStreams <= 0) {
69049e185fSopenharmony_ci        return false;
70049e185fSopenharmony_ci    }
71049e185fSopenharmony_ci    if (audioRenderInfo.contentType < AudioStandard::CONTENT_TYPE_UNKNOWN
72049e185fSopenharmony_ci        || audioRenderInfo.contentType > AudioStandard::CONTENT_TYPE_ULTRASONIC
73049e185fSopenharmony_ci        || audioRenderInfo.streamUsage < AudioStandard::STREAM_USAGE_UNKNOWN
74049e185fSopenharmony_ci        || audioRenderInfo.streamUsage > AudioStandard::STREAM_USAGE_VOICE_MODEM_COMMUNICATION
75049e185fSopenharmony_ci        || audioRenderInfo.rendererFlags < 0 || audioRenderInfo.rendererFlags > 1) {
76049e185fSopenharmony_ci        return false;
77049e185fSopenharmony_ci    }
78049e185fSopenharmony_ci    return true;
79049e185fSopenharmony_ci}
80049e185fSopenharmony_ci
81049e185fSopenharmony_ciint32_t SoundPool::Load(const std::string url)
82049e185fSopenharmony_ci{
83049e185fSopenharmony_ci    MediaTrace trace("SoundPool::Load url");
84049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
85049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::Load url::%{public}s", url.c_str());
86049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(!url.empty(), -1, "Failed to obtain SoundPool for load");
87049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
88049e185fSopenharmony_ci    return soundIDManager_->Load(url);
89049e185fSopenharmony_ci}
90049e185fSopenharmony_ci
91049e185fSopenharmony_ciint32_t SoundPool::Load(int32_t fd, int64_t offset, int64_t length)
92049e185fSopenharmony_ci{
93049e185fSopenharmony_ci    MediaTrace trace("SoundPool::Load fd");
94049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
95049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::Load fd::%{public}d, offset::%{public}s, length::%{public}s", fd,
96049e185fSopenharmony_ci        std::to_string(offset).c_str(), std::to_string(length).c_str());
97049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG((fd > 0 && length > 0 && offset >= 0), -1, "Invalid fd param.");
98049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
99049e185fSopenharmony_ci    return soundIDManager_->Load(fd, offset, length);
100049e185fSopenharmony_ci}
101049e185fSopenharmony_ci
102049e185fSopenharmony_ciint32_t SoundPool::Play(int32_t soundID, PlayParams playParameters)
103049e185fSopenharmony_ci{
104049e185fSopenharmony_ci    MediaTrace trace("SoundPool::Play");
105049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
106049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::Play soundID::%{public}d ,priority::%{public}d", soundID, playParameters.priority);
107049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, -1, "sound pool have released.");
108049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
109049e185fSopenharmony_ci    std::shared_ptr<SoundParser> soundParser = soundIDManager_->FindSoundParser(soundID);
110049e185fSopenharmony_ci
111049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(soundParser != nullptr, -1, "Invalid sound.");
112049e185fSopenharmony_ci    if (!soundParser->IsSoundParserCompleted()) {
113049e185fSopenharmony_ci        MEDIA_LOGE("sound load no completed. ");
114049e185fSopenharmony_ci        return -1;
115049e185fSopenharmony_ci    }
116049e185fSopenharmony_ci    const int32_t streamID = streamIdManager_->Play(soundParser, playParameters);
117049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::Play streamID::%{public}d", streamID);
118049e185fSopenharmony_ci    return streamID;
119049e185fSopenharmony_ci}
120049e185fSopenharmony_ci
121049e185fSopenharmony_ciint32_t SoundPool::Stop(int32_t streamID)
122049e185fSopenharmony_ci{
123049e185fSopenharmony_ci    MediaTrace trace("SoundPool::Stop");
124049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
125049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::Stop streamID::%{public}d", streamID);
126049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
127049e185fSopenharmony_ci    if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
128049e185fSopenharmony_ci        return cacheBuffer->Stop(streamID);
129049e185fSopenharmony_ci    }
130049e185fSopenharmony_ci    return MSERR_INVALID_OPERATION;
131049e185fSopenharmony_ci}
132049e185fSopenharmony_ci
133049e185fSopenharmony_ciint32_t SoundPool::SetLoop(int32_t streamID, int32_t loop)
134049e185fSopenharmony_ci{
135049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
136049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::SetLoop streamID:%{public}d, loop:%{public}d", streamID, loop);
137049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
138049e185fSopenharmony_ci    if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
139049e185fSopenharmony_ci        return cacheBuffer->SetLoop(streamID, loop);
140049e185fSopenharmony_ci    }
141049e185fSopenharmony_ci    return MSERR_INVALID_OPERATION;
142049e185fSopenharmony_ci}
143049e185fSopenharmony_ci
144049e185fSopenharmony_ciint32_t SoundPool::SetPriority(int32_t streamID, int32_t priority)
145049e185fSopenharmony_ci{
146049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
147049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::SetPriority streamID::%{public}d ,priority::%{public}d", streamID, priority);
148049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
149049e185fSopenharmony_ci    if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
150049e185fSopenharmony_ci        if (priority < MIN_STREAM_PRIORITY) {
151049e185fSopenharmony_ci            MEDIA_LOGI("Invalid priority, align priority to min.");
152049e185fSopenharmony_ci            priority = MIN_STREAM_PRIORITY;
153049e185fSopenharmony_ci        }
154049e185fSopenharmony_ci        int32_t ret = cacheBuffer->SetPriority(streamID, priority);
155049e185fSopenharmony_ci        streamIdManager_->ReorderStream(streamID, priority);
156049e185fSopenharmony_ci        return ret;
157049e185fSopenharmony_ci    }
158049e185fSopenharmony_ci    return MSERR_INVALID_OPERATION;
159049e185fSopenharmony_ci}
160049e185fSopenharmony_ci
161049e185fSopenharmony_ciint32_t SoundPool::SetRate(int32_t streamID, AudioStandard::AudioRendererRate renderRate)
162049e185fSopenharmony_ci{
163049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
164049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::SetRate streamID:%{public}d, renderRate:%{public}d", streamID, renderRate);
165049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
166049e185fSopenharmony_ci    if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
167049e185fSopenharmony_ci        return cacheBuffer->SetRate(streamID, renderRate);
168049e185fSopenharmony_ci    }
169049e185fSopenharmony_ci    return MSERR_INVALID_OPERATION;
170049e185fSopenharmony_ci}
171049e185fSopenharmony_ci
172049e185fSopenharmony_ciint32_t SoundPool::SetVolume(int32_t streamID, float leftVolume, float rightVolume)
173049e185fSopenharmony_ci{
174049e185fSopenharmony_ci    if (!CheckVolumeVaild(&leftVolume, &rightVolume)) {
175049e185fSopenharmony_ci        return MSERR_INVALID_VAL;
176049e185fSopenharmony_ci    }
177049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::SetVolume streamID:%{public}d, leftVolume:%{public}f, rightVolume:%{public}f",
178049e185fSopenharmony_ci        streamID, leftVolume, rightVolume);
179049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, MSERR_INVALID_VAL, "sound pool have released.");
180049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
181049e185fSopenharmony_ci    if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
182049e185fSopenharmony_ci        return cacheBuffer->SetVolume(streamID, leftVolume, rightVolume);
183049e185fSopenharmony_ci    }
184049e185fSopenharmony_ci    return MSERR_INVALID_OPERATION;
185049e185fSopenharmony_ci}
186049e185fSopenharmony_ci
187049e185fSopenharmony_ciint32_t SoundPool::Unload(int32_t soundID)
188049e185fSopenharmony_ci{
189049e185fSopenharmony_ci    MediaTrace trace("SoundPool::Unload");
190049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
191049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::Unload soundID::%{public}d", soundID);
192049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(streamIdManager_ != nullptr, -1, "sound pool have released.");
193049e185fSopenharmony_ci    CHECK_AND_RETURN_RET_LOG(soundIDManager_ != nullptr, -1, "sound id manager have released.");
194049e185fSopenharmony_ci    int32_t streamID = streamIdManager_->GetStreamIDBySoundID(soundID);
195049e185fSopenharmony_ci    if (std::shared_ptr<CacheBuffer> cacheBuffer = streamIdManager_->FindCacheBuffer(streamID)) {
196049e185fSopenharmony_ci        cacheBuffer->Stop(streamID);
197049e185fSopenharmony_ci        cacheBuffer->Release();
198049e185fSopenharmony_ci        streamIdManager_->ClearStreamIDInDeque(streamID);
199049e185fSopenharmony_ci    }
200049e185fSopenharmony_ci    return soundIDManager_->Unload(soundID);
201049e185fSopenharmony_ci}
202049e185fSopenharmony_ci
203049e185fSopenharmony_ciint32_t SoundPool::Release()
204049e185fSopenharmony_ci{
205049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::Release");
206049e185fSopenharmony_ci    return ReleaseInner();
207049e185fSopenharmony_ci}
208049e185fSopenharmony_ci
209049e185fSopenharmony_ciint32_t SoundPool::ReleaseInner()
210049e185fSopenharmony_ci{
211049e185fSopenharmony_ci    MediaTrace trace("SoundPool::ReleaseInner");
212049e185fSopenharmony_ci    std::lock_guard lock(soundPoolLock_);
213049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::ReleaseInner");
214049e185fSopenharmony_ci    if (streamIdManager_ != nullptr) {
215049e185fSopenharmony_ci        streamIdManager_.reset();
216049e185fSopenharmony_ci    }
217049e185fSopenharmony_ci    if (soundIDManager_ != nullptr) {
218049e185fSopenharmony_ci        soundIDManager_.reset();
219049e185fSopenharmony_ci    }
220049e185fSopenharmony_ci    if (callback_ != nullptr) {
221049e185fSopenharmony_ci        callback_.reset();
222049e185fSopenharmony_ci    }
223049e185fSopenharmony_ci    if (frameWriteCallback_ != nullptr) {
224049e185fSopenharmony_ci        frameWriteCallback_.reset();
225049e185fSopenharmony_ci    }
226049e185fSopenharmony_ci    SoundPoolManager::GetInstance().Release(getpid());
227049e185fSopenharmony_ci    return MSERR_OK;
228049e185fSopenharmony_ci}
229049e185fSopenharmony_ci
230049e185fSopenharmony_ciint32_t SoundPool::SetSoundPoolCallback(const std::shared_ptr<ISoundPoolCallback> &soundPoolCallback)
231049e185fSopenharmony_ci{
232049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::SetSoundPoolCallback");
233049e185fSopenharmony_ci    if (soundIDManager_ != nullptr) soundIDManager_->SetCallback(soundPoolCallback);
234049e185fSopenharmony_ci    if (streamIdManager_ != nullptr) streamIdManager_->SetCallback(soundPoolCallback);
235049e185fSopenharmony_ci    callback_ = soundPoolCallback;
236049e185fSopenharmony_ci    return MSERR_OK;
237049e185fSopenharmony_ci}
238049e185fSopenharmony_ci
239049e185fSopenharmony_ciint32_t SoundPool::SetSoundPoolFrameWriteCallback(
240049e185fSopenharmony_ci    const std::shared_ptr<ISoundPoolFrameWriteCallback> &frameWriteCallback)
241049e185fSopenharmony_ci{
242049e185fSopenharmony_ci    MEDIA_LOGI("SoundPool::SetSoundPoolFrameWriteCallback");
243049e185fSopenharmony_ci    if (streamIdManager_ != nullptr) streamIdManager_->SetFrameWriteCallback(frameWriteCallback);
244049e185fSopenharmony_ci    frameWriteCallback_ = frameWriteCallback;
245049e185fSopenharmony_ci    return MSERR_OK;
246049e185fSopenharmony_ci}
247049e185fSopenharmony_ci
248049e185fSopenharmony_cibool SoundPool::CheckVolumeVaild(float *leftVol, float *rightVol)
249049e185fSopenharmony_ci{
250049e185fSopenharmony_ci    if (*leftVol != std::clamp(*leftVol, 0.f, 1.f) ||
251049e185fSopenharmony_ci        *rightVol != std::clamp(*rightVol, 0.f, 1.f)) {
252049e185fSopenharmony_ci        MEDIA_LOGI("volume l=%{public}f r=%{public}f out of (0.f, 1.f) bounds, using 1.f", *leftVol, *rightVol);
253049e185fSopenharmony_ci        *leftVol = *rightVol = 1.f;
254049e185fSopenharmony_ci    }
255049e185fSopenharmony_ci    if (*leftVol != *rightVol) {
256049e185fSopenharmony_ci        MEDIA_LOGI("left volume %{public}f set not eq the right volume %{public}f ,use the left volume",
257049e185fSopenharmony_ci            *leftVol, *rightVol);
258049e185fSopenharmony_ci        *rightVol = *leftVol;
259049e185fSopenharmony_ci    }
260049e185fSopenharmony_ci    return true;
261049e185fSopenharmony_ci}
262049e185fSopenharmony_ci} // namespace Media
263049e185fSopenharmony_ci} // namespace OHOS
264