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