xref: /aosp_15_r20/frameworks/base/media/jni/soundpool/SoundPool.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2007 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "SoundPool"
19*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
20*d57664e9SAndroid Build Coastguard Worker 
21*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
22*d57664e9SAndroid Build Coastguard Worker #include <thread>
23*d57664e9SAndroid Build Coastguard Worker 
24*d57664e9SAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_AUDIO
25*d57664e9SAndroid Build Coastguard Worker #include <utils/Trace.h>
26*d57664e9SAndroid Build Coastguard Worker 
27*d57664e9SAndroid Build Coastguard Worker #include "SoundPool.h"
28*d57664e9SAndroid Build Coastguard Worker 
29*d57664e9SAndroid Build Coastguard Worker namespace android
30*d57664e9SAndroid Build Coastguard Worker {
31*d57664e9SAndroid Build Coastguard Worker 
32*d57664e9SAndroid Build Coastguard Worker // kManagerThreads = 1 historically.
33*d57664e9SAndroid Build Coastguard Worker // Not really necessary to have more than one, but it does speed things up by about
34*d57664e9SAndroid Build Coastguard Worker // 25% having 2 threads instead of 1 when playing many sounds.  Having many threads
35*d57664e9SAndroid Build Coastguard Worker // could starve other AudioFlinger clients with SoundPool activity. It may also cause
36*d57664e9SAndroid Build Coastguard Worker // issues with app loading, e.g. Camera.
37*d57664e9SAndroid Build Coastguard Worker static const size_t kStreamManagerThreads = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
38*d57664e9SAndroid Build Coastguard Worker 
39*d57664e9SAndroid Build Coastguard Worker // kUseApiLock = true prior to R.
40*d57664e9SAndroid Build Coastguard Worker // Set to true to prevent multiple users access internal to the SoundPool API.
41*d57664e9SAndroid Build Coastguard Worker // Set to false to make the SoundPool methods weakly consistent.  When set to false,
42*d57664e9SAndroid Build Coastguard Worker // only AutoPause and AutoResume are locked, which are the only two methods that
43*d57664e9SAndroid Build Coastguard Worker // require API level locking for consistency.
44*d57664e9SAndroid Build Coastguard Worker static constexpr bool kUseApiLock = false;
45*d57664e9SAndroid Build Coastguard Worker 
46*d57664e9SAndroid Build Coastguard Worker namespace {
47*d57664e9SAndroid Build Coastguard Worker // Check input arguments to SoundPool - return "true" to reject request.
48*d57664e9SAndroid Build Coastguard Worker 
checkVolume(float * leftVolume,float * rightVolume)49*d57664e9SAndroid Build Coastguard Worker bool checkVolume(float *leftVolume, float *rightVolume)
50*d57664e9SAndroid Build Coastguard Worker {
51*d57664e9SAndroid Build Coastguard Worker     if (*leftVolume != std::clamp(*leftVolume, 0.f, 1.f) ||
52*d57664e9SAndroid Build Coastguard Worker             *rightVolume != std::clamp(*rightVolume, 0.f, 1.f)) {
53*d57664e9SAndroid Build Coastguard Worker         ALOGI("volume l=%f r=%f out of (0.f, 1.f) bounds, using 1.f", *leftVolume, *rightVolume);
54*d57664e9SAndroid Build Coastguard Worker         // for backward compatibility use 1.f.
55*d57664e9SAndroid Build Coastguard Worker         *leftVolume = *rightVolume = 1.f;
56*d57664e9SAndroid Build Coastguard Worker     }
57*d57664e9SAndroid Build Coastguard Worker     return false;
58*d57664e9SAndroid Build Coastguard Worker }
59*d57664e9SAndroid Build Coastguard Worker 
checkRate(float * rate)60*d57664e9SAndroid Build Coastguard Worker bool checkRate(float *rate)
61*d57664e9SAndroid Build Coastguard Worker {
62*d57664e9SAndroid Build Coastguard Worker     if (*rate != std::clamp(*rate, 0.125f, 8.f)) {
63*d57664e9SAndroid Build Coastguard Worker         ALOGI("rate %f out of (0.125f, 8.f) bounds, clamping", *rate);
64*d57664e9SAndroid Build Coastguard Worker         // for backward compatibility just clamp
65*d57664e9SAndroid Build Coastguard Worker         *rate = std::clamp(*rate, 0.125f, 8.f);
66*d57664e9SAndroid Build Coastguard Worker     }
67*d57664e9SAndroid Build Coastguard Worker     return false;
68*d57664e9SAndroid Build Coastguard Worker }
69*d57664e9SAndroid Build Coastguard Worker 
checkPriority(int32_t * priority)70*d57664e9SAndroid Build Coastguard Worker bool checkPriority(int32_t *priority)
71*d57664e9SAndroid Build Coastguard Worker {
72*d57664e9SAndroid Build Coastguard Worker     if (*priority < 0) {
73*d57664e9SAndroid Build Coastguard Worker         ALOGI("negative priority %d, should be >= 0.", *priority);
74*d57664e9SAndroid Build Coastguard Worker         // for backward compatibility, ignore.
75*d57664e9SAndroid Build Coastguard Worker     }
76*d57664e9SAndroid Build Coastguard Worker     return false;
77*d57664e9SAndroid Build Coastguard Worker }
78*d57664e9SAndroid Build Coastguard Worker 
checkLoop(int32_t * loop)79*d57664e9SAndroid Build Coastguard Worker bool checkLoop(int32_t *loop)
80*d57664e9SAndroid Build Coastguard Worker {
81*d57664e9SAndroid Build Coastguard Worker     if (*loop < -1) {
82*d57664e9SAndroid Build Coastguard Worker         ALOGI("loop %d, should be >= -1", *loop);
83*d57664e9SAndroid Build Coastguard Worker         *loop = -1;
84*d57664e9SAndroid Build Coastguard Worker     }
85*d57664e9SAndroid Build Coastguard Worker     return false;
86*d57664e9SAndroid Build Coastguard Worker }
87*d57664e9SAndroid Build Coastguard Worker 
88*d57664e9SAndroid Build Coastguard Worker } // namespace
89*d57664e9SAndroid Build Coastguard Worker 
SoundPool(int32_t maxStreams,const audio_attributes_t & attributes,const std::string & opPackageName)90*d57664e9SAndroid Build Coastguard Worker SoundPool::SoundPool(
91*d57664e9SAndroid Build Coastguard Worker         int32_t maxStreams, const audio_attributes_t& attributes,
92*d57664e9SAndroid Build Coastguard Worker         const std::string& opPackageName)
93*d57664e9SAndroid Build Coastguard Worker     : mStreamManager(maxStreams, kStreamManagerThreads, attributes, opPackageName)
94*d57664e9SAndroid Build Coastguard Worker {
95*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(maxStreams=%d, attr={ content_type=%d, usage=%d, flags=0x%x, tags=%s })",
96*d57664e9SAndroid Build Coastguard Worker             __func__, maxStreams,
97*d57664e9SAndroid Build Coastguard Worker             attributes.content_type, attributes.usage, attributes.flags, attributes.tags);
98*d57664e9SAndroid Build Coastguard Worker }
99*d57664e9SAndroid Build Coastguard Worker 
~SoundPool()100*d57664e9SAndroid Build Coastguard Worker SoundPool::~SoundPool()
101*d57664e9SAndroid Build Coastguard Worker {
102*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
103*d57664e9SAndroid Build Coastguard Worker }
104*d57664e9SAndroid Build Coastguard Worker 
load(int fd,int64_t offset,int64_t length,int32_t priority)105*d57664e9SAndroid Build Coastguard Worker int32_t SoundPool::load(int fd, int64_t offset, int64_t length, int32_t priority)
106*d57664e9SAndroid Build Coastguard Worker {
107*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
108*d57664e9SAndroid Build Coastguard Worker             __func__, fd, (long long)offset, (long long)length, priority);
109*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
110*d57664e9SAndroid Build Coastguard Worker     return mSoundManager.load(fd, offset, length, priority);
111*d57664e9SAndroid Build Coastguard Worker }
112*d57664e9SAndroid Build Coastguard Worker 
unload(int32_t soundID)113*d57664e9SAndroid Build Coastguard Worker bool SoundPool::unload(int32_t soundID)
114*d57664e9SAndroid Build Coastguard Worker {
115*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d)", __func__, soundID);
116*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
117*d57664e9SAndroid Build Coastguard Worker     return mSoundManager.unload(soundID);
118*d57664e9SAndroid Build Coastguard Worker }
119*d57664e9SAndroid Build Coastguard Worker 
play(int32_t soundID,float leftVolume,float rightVolume,int32_t priority,int32_t loop,float rate,int32_t playerIId)120*d57664e9SAndroid Build Coastguard Worker int32_t SoundPool::play(int32_t soundID, float leftVolume, float rightVolume,
121*d57664e9SAndroid Build Coastguard Worker         int32_t priority, int32_t loop, float rate, int32_t playerIId)
122*d57664e9SAndroid Build Coastguard Worker {
123*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f)",
124*d57664e9SAndroid Build Coastguard Worker             __func__, soundID, leftVolume, rightVolume, priority, loop, rate);
125*d57664e9SAndroid Build Coastguard Worker 
126*d57664e9SAndroid Build Coastguard Worker     // New for R: check arguments to ensure track can be created.
127*d57664e9SAndroid Build Coastguard Worker     // If SoundPool defers the creation of the AudioTrack to the StreamManager thread,
128*d57664e9SAndroid Build Coastguard Worker     // the failure to create may not be visible to the caller, so this precheck is needed.
129*d57664e9SAndroid Build Coastguard Worker     if (checkVolume(&leftVolume, &rightVolume)
130*d57664e9SAndroid Build Coastguard Worker             || checkPriority(&priority)
131*d57664e9SAndroid Build Coastguard Worker             || checkLoop(&loop)
132*d57664e9SAndroid Build Coastguard Worker             || checkRate(&rate)) return 0;
133*d57664e9SAndroid Build Coastguard Worker 
134*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
135*d57664e9SAndroid Build Coastguard Worker     const std::shared_ptr<soundpool::Sound> sound = mSoundManager.findSound(soundID);
136*d57664e9SAndroid Build Coastguard Worker     if (sound == nullptr || sound->getState() != soundpool::Sound::READY) {
137*d57664e9SAndroid Build Coastguard Worker         ALOGW("%s soundID %d not READY", __func__, soundID);
138*d57664e9SAndroid Build Coastguard Worker         return 0;
139*d57664e9SAndroid Build Coastguard Worker     }
140*d57664e9SAndroid Build Coastguard Worker 
141*d57664e9SAndroid Build Coastguard Worker     ATRACE_BEGIN("SoundPool::play (native)");
142*d57664e9SAndroid Build Coastguard Worker     const int32_t streamID = mStreamManager.queueForPlay(
143*d57664e9SAndroid Build Coastguard Worker             sound, soundID, leftVolume, rightVolume, priority, loop, rate, playerIId);
144*d57664e9SAndroid Build Coastguard Worker     ATRACE_END();
145*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s returned %d", __func__, streamID);
146*d57664e9SAndroid Build Coastguard Worker 
147*d57664e9SAndroid Build Coastguard Worker     return streamID;
148*d57664e9SAndroid Build Coastguard Worker }
149*d57664e9SAndroid Build Coastguard Worker 
autoPause()150*d57664e9SAndroid Build Coastguard Worker void SoundPool::autoPause()
151*d57664e9SAndroid Build Coastguard Worker {
152*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
153*d57664e9SAndroid Build Coastguard Worker     auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
154*d57664e9SAndroid Build Coastguard Worker     mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoPause(); });
155*d57664e9SAndroid Build Coastguard Worker }
156*d57664e9SAndroid Build Coastguard Worker 
autoResume()157*d57664e9SAndroid Build Coastguard Worker void SoundPool::autoResume()
158*d57664e9SAndroid Build Coastguard Worker {
159*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
160*d57664e9SAndroid Build Coastguard Worker     auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
161*d57664e9SAndroid Build Coastguard Worker     mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoResume(); });
162*d57664e9SAndroid Build Coastguard Worker }
163*d57664e9SAndroid Build Coastguard Worker 
mute(bool muting)164*d57664e9SAndroid Build Coastguard Worker void SoundPool::mute(bool muting)
165*d57664e9SAndroid Build Coastguard Worker {
166*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d)", __func__, muting);
167*d57664e9SAndroid Build Coastguard Worker     auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
168*d57664e9SAndroid Build Coastguard Worker     mStreamManager.forEach([=](soundpool::Stream *stream) { stream->mute(muting); });
169*d57664e9SAndroid Build Coastguard Worker }
170*d57664e9SAndroid Build Coastguard Worker 
pause(int32_t streamID)171*d57664e9SAndroid Build Coastguard Worker void SoundPool::pause(int32_t streamID)
172*d57664e9SAndroid Build Coastguard Worker {
173*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d)", __func__, streamID);
174*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
175*d57664e9SAndroid Build Coastguard Worker     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
176*d57664e9SAndroid Build Coastguard Worker         stream->pause(streamID);
177*d57664e9SAndroid Build Coastguard Worker     }
178*d57664e9SAndroid Build Coastguard Worker }
179*d57664e9SAndroid Build Coastguard Worker 
resume(int32_t streamID)180*d57664e9SAndroid Build Coastguard Worker void SoundPool::resume(int32_t streamID)
181*d57664e9SAndroid Build Coastguard Worker {
182*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d)", __func__, streamID);
183*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
184*d57664e9SAndroid Build Coastguard Worker     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
185*d57664e9SAndroid Build Coastguard Worker         stream->resume(streamID);
186*d57664e9SAndroid Build Coastguard Worker     }
187*d57664e9SAndroid Build Coastguard Worker }
188*d57664e9SAndroid Build Coastguard Worker 
stop(int32_t streamID)189*d57664e9SAndroid Build Coastguard Worker void SoundPool::stop(int32_t streamID)
190*d57664e9SAndroid Build Coastguard Worker {
191*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d)", __func__, streamID);
192*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
193*d57664e9SAndroid Build Coastguard Worker     soundpool::Stream* stream = mStreamManager.findStream(streamID);
194*d57664e9SAndroid Build Coastguard Worker     if (stream != nullptr && stream->requestStop(streamID)) {
195*d57664e9SAndroid Build Coastguard Worker         mStreamManager.moveToRestartQueue(stream, streamID);
196*d57664e9SAndroid Build Coastguard Worker     }
197*d57664e9SAndroid Build Coastguard Worker }
198*d57664e9SAndroid Build Coastguard Worker 
setVolume(int32_t streamID,float leftVolume,float rightVolume)199*d57664e9SAndroid Build Coastguard Worker void SoundPool::setVolume(int32_t streamID, float leftVolume, float rightVolume)
200*d57664e9SAndroid Build Coastguard Worker {
201*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d, %f %f)", __func__, streamID, leftVolume, rightVolume);
202*d57664e9SAndroid Build Coastguard Worker     if (checkVolume(&leftVolume, &rightVolume)) return;
203*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
204*d57664e9SAndroid Build Coastguard Worker     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
205*d57664e9SAndroid Build Coastguard Worker         stream->setVolume(streamID, leftVolume, rightVolume);
206*d57664e9SAndroid Build Coastguard Worker     }
207*d57664e9SAndroid Build Coastguard Worker }
208*d57664e9SAndroid Build Coastguard Worker 
setPriority(int32_t streamID,int32_t priority)209*d57664e9SAndroid Build Coastguard Worker void SoundPool::setPriority(int32_t streamID, int32_t priority)
210*d57664e9SAndroid Build Coastguard Worker {
211*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d, %d)", __func__, streamID, priority);
212*d57664e9SAndroid Build Coastguard Worker     if (checkPriority(&priority)) return;
213*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
214*d57664e9SAndroid Build Coastguard Worker     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
215*d57664e9SAndroid Build Coastguard Worker         stream->setPriority(streamID, priority);
216*d57664e9SAndroid Build Coastguard Worker     }
217*d57664e9SAndroid Build Coastguard Worker }
218*d57664e9SAndroid Build Coastguard Worker 
setLoop(int32_t streamID,int32_t loop)219*d57664e9SAndroid Build Coastguard Worker void SoundPool::setLoop(int32_t streamID, int32_t loop)
220*d57664e9SAndroid Build Coastguard Worker {
221*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d, %d)", __func__, streamID, loop);
222*d57664e9SAndroid Build Coastguard Worker     if (checkLoop(&loop)) return;
223*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
224*d57664e9SAndroid Build Coastguard Worker     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
225*d57664e9SAndroid Build Coastguard Worker         stream->setLoop(streamID, loop);
226*d57664e9SAndroid Build Coastguard Worker     }
227*d57664e9SAndroid Build Coastguard Worker }
228*d57664e9SAndroid Build Coastguard Worker 
setRate(int32_t streamID,float rate)229*d57664e9SAndroid Build Coastguard Worker void SoundPool::setRate(int32_t streamID, float rate)
230*d57664e9SAndroid Build Coastguard Worker {
231*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%d, %f)", __func__, streamID, rate);
232*d57664e9SAndroid Build Coastguard Worker     if (checkRate(&rate)) return;
233*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
234*d57664e9SAndroid Build Coastguard Worker     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
235*d57664e9SAndroid Build Coastguard Worker         stream->setRate(streamID, rate);
236*d57664e9SAndroid Build Coastguard Worker     }
237*d57664e9SAndroid Build Coastguard Worker }
238*d57664e9SAndroid Build Coastguard Worker 
setCallback(SoundPoolCallback * callback,void * user)239*d57664e9SAndroid Build Coastguard Worker void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
240*d57664e9SAndroid Build Coastguard Worker {
241*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s(%p, %p)", __func__, callback, user);
242*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
243*d57664e9SAndroid Build Coastguard Worker     mSoundManager.setCallback(this, callback, user);
244*d57664e9SAndroid Build Coastguard Worker }
245*d57664e9SAndroid Build Coastguard Worker 
getUserData() const246*d57664e9SAndroid Build Coastguard Worker void* SoundPool::getUserData() const
247*d57664e9SAndroid Build Coastguard Worker {
248*d57664e9SAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
249*d57664e9SAndroid Build Coastguard Worker     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
250*d57664e9SAndroid Build Coastguard Worker     return mSoundManager.getUserData();
251*d57664e9SAndroid Build Coastguard Worker }
252*d57664e9SAndroid Build Coastguard Worker 
253*d57664e9SAndroid Build Coastguard Worker } // end namespace android
254