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 #include "SoundPool.h"
25
26 namespace android
27 {
28
29 // kManagerThreads = 1 historically.
30 // Not really necessary to have more than one, but it does speed things up by about
31 // 25% having 2 threads instead of 1 when playing many sounds. Having many threads
32 // could starve other AudioFlinger clients with SoundPool activity. It may also cause
33 // issues with app loading, e.g. Camera.
34 static const size_t kStreamManagerThreads = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
35
36 // kUseApiLock = true prior to R.
37 // Set to true to prevent multiple users access internal to the SoundPool API.
38 // Set to false to make the SoundPool methods weakly consistent. When set to false,
39 // only AutoPause and AutoResume are locked, which are the only two methods that
40 // require API level locking for consistency.
41 static constexpr bool kUseApiLock = false;
42
43 namespace {
44 // Check input arguments to SoundPool - return "true" to reject request.
45
checkVolume(float * leftVolume,float * rightVolume)46 bool checkVolume(float *leftVolume, float *rightVolume)
47 {
48 if (*leftVolume != std::clamp(*leftVolume, 0.f, 1.f) ||
49 *rightVolume != std::clamp(*rightVolume, 0.f, 1.f)) {
50 ALOGI("volume l=%f r=%f out of (0.f, 1.f) bounds, using 1.f", *leftVolume, *rightVolume);
51 // for backward compatibility use 1.f.
52 *leftVolume = *rightVolume = 1.f;
53 }
54 return false;
55 }
56
checkRate(float * rate)57 bool checkRate(float *rate)
58 {
59 if (*rate != std::clamp(*rate, 0.125f, 8.f)) {
60 ALOGI("rate %f out of (0.125f, 8.f) bounds, clamping", *rate);
61 // for backward compatibility just clamp
62 *rate = std::clamp(*rate, 0.125f, 8.f);
63 }
64 return false;
65 }
66
checkPriority(int32_t * priority)67 bool checkPriority(int32_t *priority)
68 {
69 if (*priority < 0) {
70 ALOGI("negative priority %d, should be >= 0.", *priority);
71 // for backward compatibility, ignore.
72 }
73 return false;
74 }
75
checkLoop(int32_t * loop)76 bool checkLoop(int32_t *loop)
77 {
78 if (*loop < -1) {
79 ALOGI("loop %d, should be >= -1", *loop);
80 *loop = -1;
81 }
82 return false;
83 }
84
85 } // namespace
86
SoundPool(int32_t maxStreams,const audio_attributes_t * attributes)87 SoundPool::SoundPool(int32_t maxStreams, const audio_attributes_t* attributes)
88 : mStreamManager(maxStreams, kStreamManagerThreads, attributes)
89 {
90 ALOGV("%s(maxStreams=%d, attr={ content_type=%d, usage=%d, flags=0x%x, tags=%s })",
91 __func__, maxStreams,
92 attributes->content_type, attributes->usage, attributes->flags, attributes->tags);
93 }
94
~SoundPool()95 SoundPool::~SoundPool()
96 {
97 ALOGV("%s()", __func__);
98 }
99
load(int fd,int64_t offset,int64_t length,int32_t priority)100 int32_t SoundPool::load(int fd, int64_t offset, int64_t length, int32_t priority)
101 {
102 ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
103 __func__, fd, (long long)offset, (long long)length, priority);
104 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
105 return mSoundManager.load(fd, offset, length, priority);
106 }
107
unload(int32_t soundID)108 bool SoundPool::unload(int32_t soundID)
109 {
110 ALOGV("%s(%d)", __func__, soundID);
111 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
112 return mSoundManager.unload(soundID);
113 }
114
play(int32_t soundID,float leftVolume,float rightVolume,int32_t priority,int32_t loop,float rate)115 int32_t SoundPool::play(int32_t soundID, float leftVolume, float rightVolume,
116 int32_t priority, int32_t loop, float rate)
117 {
118 ALOGV("%s(soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f)",
119 __func__, soundID, leftVolume, rightVolume, priority, loop, rate);
120
121 // New for R: check arguments to ensure track can be created.
122 // If SoundPool defers the creation of the AudioTrack to the StreamManager thread,
123 // the failure to create may not be visible to the caller, so this precheck is needed.
124 if (checkVolume(&leftVolume, &rightVolume)
125 || checkPriority(&priority)
126 || checkLoop(&loop)
127 || checkRate(&rate)) return 0;
128
129 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
130 const std::shared_ptr<soundpool::Sound> sound = mSoundManager.findSound(soundID);
131 if (sound == nullptr || sound->getState() != soundpool::Sound::READY) {
132 ALOGW("%s soundID %d not READY", __func__, soundID);
133 return 0;
134 }
135
136 const int32_t streamID = mStreamManager.queueForPlay(
137 sound, soundID, leftVolume, rightVolume, priority, loop, rate);
138 ALOGV("%s returned %d", __func__, streamID);
139 return streamID;
140 }
141
autoPause()142 void SoundPool::autoPause()
143 {
144 ALOGV("%s()", __func__);
145 auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
146 mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoPause(); });
147 }
148
autoResume()149 void SoundPool::autoResume()
150 {
151 ALOGV("%s()", __func__);
152 auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
153 mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoResume(); });
154 }
155
mute(bool muting)156 void SoundPool::mute(bool muting)
157 {
158 ALOGV("%s(%d)", __func__, muting);
159 auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
160 mStreamManager.forEach([=](soundpool::Stream *stream) { stream->mute(muting); });
161 }
162
pause(int32_t streamID)163 void SoundPool::pause(int32_t streamID)
164 {
165 ALOGV("%s(%d)", __func__, streamID);
166 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
167 if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
168 stream->pause(streamID);
169 }
170 }
171
resume(int32_t streamID)172 void SoundPool::resume(int32_t streamID)
173 {
174 ALOGV("%s(%d)", __func__, streamID);
175 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
176 if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
177 stream->resume(streamID);
178 }
179 }
180
stop(int32_t streamID)181 void SoundPool::stop(int32_t streamID)
182 {
183 ALOGV("%s(%d)", __func__, streamID);
184 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
185 soundpool::Stream* stream = mStreamManager.findStream(streamID);
186 if (stream != nullptr && stream->requestStop(streamID)) {
187 mStreamManager.moveToRestartQueue(stream);
188 }
189 }
190
setVolume(int32_t streamID,float leftVolume,float rightVolume)191 void SoundPool::setVolume(int32_t streamID, float leftVolume, float rightVolume)
192 {
193 ALOGV("%s(%d, %f %f)", __func__, streamID, leftVolume, rightVolume);
194 if (checkVolume(&leftVolume, &rightVolume)) return;
195 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
196 if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
197 stream->setVolume(streamID, leftVolume, rightVolume);
198 }
199 }
200
setPriority(int32_t streamID,int32_t priority)201 void SoundPool::setPriority(int32_t streamID, int32_t priority)
202 {
203 ALOGV("%s(%d, %d)", __func__, streamID, priority);
204 if (checkPriority(&priority)) return;
205 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
206 if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
207 stream->setPriority(streamID, priority);
208 }
209 }
210
setLoop(int32_t streamID,int32_t loop)211 void SoundPool::setLoop(int32_t streamID, int32_t loop)
212 {
213 ALOGV("%s(%d, %d)", __func__, streamID, loop);
214 if (checkLoop(&loop)) return;
215 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
216 if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
217 stream->setLoop(streamID, loop);
218 }
219 }
220
setRate(int32_t streamID,float rate)221 void SoundPool::setRate(int32_t streamID, float rate)
222 {
223 ALOGV("%s(%d, %f)", __func__, streamID, rate);
224 if (checkRate(&rate)) return;
225 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
226 if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
227 stream->setRate(streamID, rate);
228 }
229 }
230
setCallback(SoundPoolCallback * callback,void * user)231 void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
232 {
233 ALOGV("%s(%p, %p)", __func__, callback, user);
234 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
235 mSoundManager.setCallback(this, callback, user);
236 }
237
getUserData() const238 void* SoundPool::getUserData() const
239 {
240 ALOGV("%s()", __func__);
241 auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
242 return mSoundManager.getUserData();
243 }
244
245 } // end namespace android
246