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,const std::string & opPackageName)87 SoundPool::SoundPool(
88         int32_t maxStreams, const audio_attributes_t& attributes,
89         const std::string& opPackageName)
90     : mStreamManager(maxStreams, kStreamManagerThreads, attributes, opPackageName)
91 {
92     ALOGV("%s(maxStreams=%d, attr={ content_type=%d, usage=%d, flags=0x%x, tags=%s })",
93             __func__, maxStreams,
94             attributes.content_type, attributes.usage, attributes.flags, attributes.tags);
95 }
96 
~SoundPool()97 SoundPool::~SoundPool()
98 {
99     ALOGV("%s()", __func__);
100 }
101 
load(int fd,int64_t offset,int64_t length,int32_t priority)102 int32_t SoundPool::load(int fd, int64_t offset, int64_t length, int32_t priority)
103 {
104     ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)",
105             __func__, fd, (long long)offset, (long long)length, priority);
106     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
107     return mSoundManager.load(fd, offset, length, priority);
108 }
109 
unload(int32_t soundID)110 bool SoundPool::unload(int32_t soundID)
111 {
112     ALOGV("%s(%d)", __func__, soundID);
113     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
114     return mSoundManager.unload(soundID);
115 }
116 
play(int32_t soundID,float leftVolume,float rightVolume,int32_t priority,int32_t loop,float rate,int32_t playerIId)117 int32_t SoundPool::play(int32_t soundID, float leftVolume, float rightVolume,
118         int32_t priority, int32_t loop, float rate, int32_t playerIId)
119 {
120     ALOGV("%s(soundID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f)",
121             __func__, soundID, leftVolume, rightVolume, priority, loop, rate);
122 
123     // New for R: check arguments to ensure track can be created.
124     // If SoundPool defers the creation of the AudioTrack to the StreamManager thread,
125     // the failure to create may not be visible to the caller, so this precheck is needed.
126     if (checkVolume(&leftVolume, &rightVolume)
127             || checkPriority(&priority)
128             || checkLoop(&loop)
129             || checkRate(&rate)) return 0;
130 
131     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
132     const std::shared_ptr<soundpool::Sound> sound = mSoundManager.findSound(soundID);
133     if (sound == nullptr || sound->getState() != soundpool::Sound::READY) {
134         ALOGW("%s soundID %d not READY", __func__, soundID);
135         return 0;
136     }
137 
138     const int32_t streamID = mStreamManager.queueForPlay(
139             sound, soundID, leftVolume, rightVolume, priority, loop, rate, playerIId);
140     ALOGV("%s returned %d", __func__, streamID);
141 
142     return streamID;
143 }
144 
autoPause()145 void SoundPool::autoPause()
146 {
147     ALOGV("%s()", __func__);
148     auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
149     mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoPause(); });
150 }
151 
autoResume()152 void SoundPool::autoResume()
153 {
154     ALOGV("%s()", __func__);
155     auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
156     mStreamManager.forEach([](soundpool::Stream *stream) { stream->autoResume(); });
157 }
158 
mute(bool muting)159 void SoundPool::mute(bool muting)
160 {
161     ALOGV("%s(%d)", __func__, muting);
162     auto apiLock = std::make_unique<std::lock_guard<std::mutex>>(mApiLock);
163     mStreamManager.forEach([=](soundpool::Stream *stream) { stream->mute(muting); });
164 }
165 
pause(int32_t streamID)166 void SoundPool::pause(int32_t streamID)
167 {
168     ALOGV("%s(%d)", __func__, streamID);
169     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
170     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
171         stream->pause(streamID);
172     }
173 }
174 
resume(int32_t streamID)175 void SoundPool::resume(int32_t streamID)
176 {
177     ALOGV("%s(%d)", __func__, streamID);
178     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
179     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
180         stream->resume(streamID);
181     }
182 }
183 
stop(int32_t streamID)184 void SoundPool::stop(int32_t streamID)
185 {
186     ALOGV("%s(%d)", __func__, streamID);
187     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
188     soundpool::Stream* stream = mStreamManager.findStream(streamID);
189     if (stream != nullptr && stream->requestStop(streamID)) {
190         mStreamManager.moveToRestartQueue(stream, streamID);
191     }
192 }
193 
setVolume(int32_t streamID,float leftVolume,float rightVolume)194 void SoundPool::setVolume(int32_t streamID, float leftVolume, float rightVolume)
195 {
196     ALOGV("%s(%d, %f %f)", __func__, streamID, leftVolume, rightVolume);
197     if (checkVolume(&leftVolume, &rightVolume)) return;
198     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
199     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
200         stream->setVolume(streamID, leftVolume, rightVolume);
201     }
202 }
203 
setPriority(int32_t streamID,int32_t priority)204 void SoundPool::setPriority(int32_t streamID, int32_t priority)
205 {
206     ALOGV("%s(%d, %d)", __func__, streamID, priority);
207     if (checkPriority(&priority)) return;
208     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
209     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
210         stream->setPriority(streamID, priority);
211     }
212 }
213 
setLoop(int32_t streamID,int32_t loop)214 void SoundPool::setLoop(int32_t streamID, int32_t loop)
215 {
216     ALOGV("%s(%d, %d)", __func__, streamID, loop);
217     if (checkLoop(&loop)) return;
218     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
219     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
220         stream->setLoop(streamID, loop);
221     }
222 }
223 
setRate(int32_t streamID,float rate)224 void SoundPool::setRate(int32_t streamID, float rate)
225 {
226     ALOGV("%s(%d, %f)", __func__, streamID, rate);
227     if (checkRate(&rate)) return;
228     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
229     if (soundpool::Stream* stream = mStreamManager.findStream(streamID)) {
230         stream->setRate(streamID, rate);
231     }
232 }
233 
setCallback(SoundPoolCallback * callback,void * user)234 void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
235 {
236     ALOGV("%s(%p, %p)", __func__, callback, user);
237     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
238     mSoundManager.setCallback(this, callback, user);
239 }
240 
getUserData() const241 void* SoundPool::getUserData() const
242 {
243     ALOGV("%s()", __func__);
244     auto apiLock = kUseApiLock ? std::make_unique<std::lock_guard<std::mutex>>(mApiLock) : nullptr;
245     return mSoundManager.getUserData();
246 }
247 
248 } // end namespace android
249