1 /*
2  * Copyright (C) 2019 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::Stream"
19 #include <utils/Log.h>
20 
21 #include "Stream.h"
22 
23 #include "StreamManager.h"
24 
25 namespace android::soundpool {
26 
~Stream()27 Stream::~Stream()
28 {
29     ALOGV("%s(%p)", __func__, this);
30 }
31 
autoPause()32 void Stream::autoPause()
33 {
34     std::lock_guard lock(mLock);
35     if (mState == PLAYING) {
36         ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
37         mState = PAUSED;
38         mAutoPaused = true;
39         if (mAudioTrack != nullptr) {
40             mAudioTrack->pause();
41         }
42     }
43 }
44 
autoResume()45 void Stream::autoResume()
46 {
47     std::lock_guard lock(mLock);
48     if (mAutoPaused) {
49         if (mState == PAUSED) {
50             ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
51             mState = PLAYING;
52             if (mAudioTrack != nullptr) {
53                 mAudioTrack->start();
54             }
55         }
56         mAutoPaused = false; // New for R: always reset autopause (consistent with API spec).
57     }
58 }
59 
mute(bool muting)60 void Stream::mute(bool muting)
61 {
62     std::lock_guard lock(mLock);
63     mMuted = muting;
64     if (mAudioTrack != nullptr) {
65         if (mMuted) {
66             mAudioTrack->setVolume(0.0f, 0.0f);
67         } else {
68             mAudioTrack->setVolume(mLeftVolume, mRightVolume);
69         }
70     }
71 }
72 
pause(int32_t streamID)73 void Stream::pause(int32_t streamID)
74 {
75     std::lock_guard lock(mLock);
76     if (streamID == mStreamID) {
77         if (mState == PLAYING) {
78             ALOGV("%s: track streamID: %d", __func__, streamID);
79             mState = PAUSED;
80             if (mAudioTrack != nullptr) {
81                 mAudioTrack->pause();
82             }
83         }
84     }
85 }
86 
resume(int32_t streamID)87 void Stream::resume(int32_t streamID)
88 {
89     std::lock_guard lock(mLock);
90     if (streamID == mStreamID) {
91          if (mState == PAUSED) {
92             ALOGV("%s: track streamID: %d", __func__, streamID);
93             mState = PLAYING;
94             if (mAudioTrack != nullptr) {
95                 mAudioTrack->start();
96             }
97             mAutoPaused = false; // TODO: is this right? (ambiguous per spec), move outside?
98         }
99     }
100 }
101 
setRate(int32_t streamID,float rate)102 void Stream::setRate(int32_t streamID, float rate)
103 {
104     std::lock_guard lock(mLock);
105     if (streamID == mStreamID) {
106         mRate = rate;
107         if (mAudioTrack != nullptr && mSound != nullptr) {
108             const auto sampleRate = (uint32_t)lround(double(mSound->getSampleRate()) * rate);
109             mAudioTrack->setSampleRate(sampleRate);
110         }
111     }
112 }
113 
setVolume_l(float leftVolume,float rightVolume)114 void Stream::setVolume_l(float leftVolume, float rightVolume)
115 {
116     mLeftVolume = leftVolume;
117     mRightVolume = rightVolume;
118     if (mAudioTrack != nullptr && !mMuted) {
119         mAudioTrack->setVolume(leftVolume, rightVolume);
120     }
121 }
122 
setVolume(int32_t streamID,float leftVolume,float rightVolume)123 void Stream::setVolume(int32_t streamID, float leftVolume, float rightVolume)
124 {
125     std::lock_guard lock(mLock);
126     if (streamID == mStreamID) {
127         setVolume_l(leftVolume, rightVolume);
128     }
129 }
130 
setPriority(int32_t streamID,int32_t priority)131 void Stream::setPriority(int32_t streamID, int32_t priority)
132 {
133     std::lock_guard lock(mLock);
134     if (streamID == mStreamID) {
135         mPriority = priority;
136     }
137 }
138 
setLoop(int32_t streamID,int32_t loop)139 void Stream::setLoop(int32_t streamID, int32_t loop)
140 {
141     std::lock_guard lock(mLock);
142     if (streamID == mStreamID) {
143         if (mAudioTrack != nullptr && mSound != nullptr) {
144             const uint32_t loopEnd = mSound->getSizeInBytes() / mSound->getChannelCount() /
145                 (mSound->getFormat() == AUDIO_FORMAT_PCM_16_BIT
146                         ? sizeof(int16_t) : sizeof(uint8_t));
147             mAudioTrack->setLoop(0, loopEnd, loop);
148         }
149         mLoop = loop;
150     }
151 }
152 
setPlay(int32_t streamID,const std::shared_ptr<Sound> & sound,int32_t soundID,float leftVolume,float rightVolume,int32_t priority,int32_t loop,float rate)153 void Stream::setPlay(
154         int32_t streamID, const std::shared_ptr<Sound> &sound, int32_t soundID,
155         float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate)
156 {
157     std::lock_guard lock(mLock);
158     // We must be idle, or we must be repurposing a pending Stream.
159     LOG_ALWAYS_FATAL_IF(mState != IDLE && mAudioTrack != nullptr, "State %d must be IDLE", mState);
160     mSound = sound;
161     mSoundID = soundID;
162     mLeftVolume = leftVolume;
163     mRightVolume = rightVolume;
164     mPriority = priority;
165     mLoop = loop;
166     mRate = rate;
167     mState = PLAYING;
168     mAutoPaused = false;   // New for R (consistent with Java API spec).
169     mStreamID = streamID;  // prefer this to be the last, as it is an atomic sync point
170 }
171 
setStopTimeNs(int64_t stopTimeNs)172 void Stream::setStopTimeNs(int64_t stopTimeNs)
173 {
174     std::lock_guard lock(mLock);
175     mStopTimeNs = stopTimeNs;
176 }
177 
requestStop(int32_t streamID)178 bool Stream::requestStop(int32_t streamID)
179 {
180     std::lock_guard lock(mLock);
181     if (streamID == mStreamID) {
182         ALOGV("%s: track streamID: %d", __func__, streamID);
183         if (mAudioTrack != nullptr) {
184             if (mState == PLAYING && !mMuted && (mLeftVolume != 0.f || mRightVolume != 0.f)) {
185                 setVolume_l(0.f, 0.f);
186                 mStopTimeNs = systemTime() + kStopWaitTimeNs;
187             } else {
188                 mStopTimeNs = systemTime();
189             }
190             return true; // must be queued on the restart list.
191         }
192         stop_l();
193     }
194     return false;
195 }
196 
stop()197 void Stream::stop()
198 {
199     std::lock_guard lock(mLock);
200     stop_l();
201 }
202 
stop_l()203 void Stream::stop_l()
204 {
205     if (mState != IDLE) {
206         ALOGV("%s: track(%p) streamID: %d", __func__, mAudioTrack.get(), (int)mStreamID);
207         if (mAudioTrack != nullptr) {
208             mAudioTrack->stop();
209         }
210         mSound.reset();
211         mState = IDLE;
212     }
213 }
214 
clearAudioTrack()215 void Stream::clearAudioTrack()
216 {
217     sp<AudioTrack> release;  // release outside of lock.
218     std::lock_guard lock(mLock);
219     // This will invoke the destructor which waits for the AudioTrack thread to join,
220     // and is currently the only safe way to ensure there are no callbacks afterwards.
221     release = mAudioTrack;  // or std::swap if we had move semantics.
222     mAudioTrack.clear();
223 }
224 
getPairStream() const225 Stream* Stream::getPairStream() const
226 {
227    return mStreamManager->getPairStream(this);
228 }
229 
playPairStream()230 Stream* Stream::playPairStream() {
231     Stream* pairStream = getPairStream();
232     LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
233     sp<AudioTrack> releaseTracks[2];
234     {
235         ALOGV("%s: track streamID: %d", __func__, (int)getStreamID());
236         // TODO: Do we really want to force a simultaneous synchronization between
237         // the stream and its pair?
238 
239         // note locking order - the paired stream is obtained before the queued stream.
240         // we can invert the locking order, but it is slightly more optimal to do it this way.
241         std::lock_guard lockp(pairStream->mLock);
242         if (pairStream->mSound == nullptr) {
243             return nullptr; // no pair sound
244         }
245         {
246             std::lock_guard lock(mLock);
247             LOG_ALWAYS_FATAL_IF(mState != IDLE, "State: %d must be IDLE", mState);
248             // TODO: do we want a specific set() here?
249             pairStream->mAudioTrack = mAudioTrack;
250             pairStream->mSoundID = mSoundID; // optimization to reuse AudioTrack.
251             pairStream->mToggle = mToggle;
252             pairStream->mAutoPaused = mAutoPaused; // save autopause state
253             pairStream->mMuted = mMuted;
254             mAudioTrack.clear();  // the pair owns the audiotrack.
255             mSound.reset();
256             mSoundID = 0;
257         }
258         // TODO: do we need a specific play_l() anymore?
259         const int pairState = pairStream->mState;
260         pairStream->play_l(pairStream->mSound, pairStream->mStreamID,
261                 pairStream->mLeftVolume, pairStream->mRightVolume, pairStream->mPriority,
262                 pairStream->mLoop, pairStream->mRate, releaseTracks);
263         if (pairStream->mState == IDLE) {
264             return nullptr; // AudioTrack error
265         }
266         if (pairState == PAUSED) {  // reestablish pause
267             pairStream->mState = PAUSED;
268             pairStream->mAudioTrack->pause();
269         }
270     }
271     // release tracks outside of Stream lock
272     return pairStream;
273 }
274 
play_l(const std::shared_ptr<Sound> & sound,int32_t nextStreamID,float leftVolume,float rightVolume,int32_t priority,int32_t loop,float rate,sp<AudioTrack> releaseTracks[2])275 void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID,
276         float leftVolume, float rightVolume, int32_t priority, int32_t loop, float rate,
277         sp<AudioTrack> releaseTracks[2])
278 {
279     // These tracks are released without the lock.
280     sp<AudioTrack> &oldTrack = releaseTracks[0];
281     sp<AudioTrack> &newTrack = releaseTracks[1];
282     status_t status = NO_ERROR;
283 
284     {
285         ALOGV("%s(%p)(soundID=%d, streamID=%d, leftVolume=%f, rightVolume=%f,"
286                 " priority=%d, loop=%d, rate=%f)",
287                 __func__, this, sound->getSoundID(), nextStreamID, leftVolume, rightVolume,
288                 priority, loop, rate);
289 
290         // initialize track
291         const audio_stream_type_t streamType =
292                 AudioSystem::attributesToStreamType(*mStreamManager->getAttributes());
293         const int32_t channelCount = sound->getChannelCount();
294         const auto sampleRate = (uint32_t)lround(double(sound->getSampleRate()) * rate);
295         size_t frameCount = 0;
296 
297         if (loop) {
298             const audio_format_t format = sound->getFormat();
299             const size_t frameSize = audio_is_linear_pcm(format)
300                     ? channelCount * audio_bytes_per_sample(format) : 1;
301             frameCount = sound->getSizeInBytes() / frameSize;
302         }
303 
304         // check if the existing track has the same sound id.
305         if (mAudioTrack != nullptr && mSoundID == sound->getSoundID()) {
306             // the sample rate may fail to change if the audio track is a fast track.
307             if (mAudioTrack->setSampleRate(sampleRate) == NO_ERROR) {
308                 newTrack = mAudioTrack;
309                 ALOGV("%s: reusing track %p for sound %d",
310                         __func__, mAudioTrack.get(), sound->getSoundID());
311             }
312         }
313         if (newTrack == nullptr) {
314             // mToggle toggles each time a track is started on a given stream.
315             // The toggle is concatenated with the Stream address and passed to AudioTrack
316             // as callback user data. This enables the detection of callbacks received from the old
317             // audio track while the new one is being started and avoids processing them with
318             // wrong audio audio buffer size  (mAudioBufferSize)
319             auto toggle = mToggle ^ 1;
320             void* userData = (void*)((uintptr_t)this | toggle);
321             audio_channel_mask_t soundChannelMask = sound->getChannelMask();
322             // When sound contains a valid channel mask, use it as is.
323             // Otherwise, use stream count to calculate channel mask.
324             audio_channel_mask_t channelMask = soundChannelMask != AUDIO_CHANNEL_NONE
325                     ? soundChannelMask : audio_channel_out_mask_from_count(channelCount);
326 
327             // do not create a new audio track if current track is compatible with sound parameters
328 
329             newTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(),
330                     channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST,
331                     staticCallback, userData,
332                     0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE,
333                     AudioTrack::TRANSFER_DEFAULT,
334                     nullptr /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/,
335                     mStreamManager->getAttributes());
336             // Set caller name so it can be logged in destructor.
337             // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL
338             newTrack->setCallerName("soundpool");
339             oldTrack = mAudioTrack;
340             status = newTrack->initCheck();
341             if (status != NO_ERROR) {
342                 ALOGE("%s: error creating AudioTrack", __func__);
343                 // newTrack goes out of scope, so reference count drops to zero
344                 goto exit;
345             }
346             // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
347             mToggle = toggle;
348             mAudioTrack = newTrack;
349             ALOGV("%s: using new track %p for sound %d",
350                     __func__, newTrack.get(), sound->getSoundID());
351         }
352         if (mMuted) {
353             newTrack->setVolume(0.0f, 0.0f);
354         } else {
355             newTrack->setVolume(leftVolume, rightVolume);
356         }
357         newTrack->setLoop(0, frameCount, loop);
358         mAudioTrack->start();
359         mSound = sound;
360         mSoundID = sound->getSoundID();
361         mPriority = priority;
362         mLoop = loop;
363         mLeftVolume = leftVolume;
364         mRightVolume = rightVolume;
365         mRate = rate;
366         mState = PLAYING;
367         mStopTimeNs = 0;
368         mStreamID = nextStreamID;  // prefer this to be the last, as it is an atomic sync point
369     }
370 
371 exit:
372     ALOGV("%s: delete oldTrack %p", __func__, oldTrack.get());
373     if (status != NO_ERROR) {
374         // TODO: should we consider keeping the soundID if the old track is OK?
375         // Do not attempt to restart this track (should we remove the stream id?)
376         mState = IDLE;
377         mSoundID = 0;
378         mSound.reset();
379         mAudioTrack.clear();  // actual release from releaseTracks[]
380     }
381 }
382 
383 /* static */
staticCallback(int event,void * user,void * info)384 void Stream::staticCallback(int event, void* user, void* info)
385 {
386     const auto userAsInt = (uintptr_t)user;
387     auto stream = reinterpret_cast<Stream*>(userAsInt & ~1);
388     stream->callback(event, info, int(userAsInt & 1), 0 /* tries */);
389 }
390 
callback(int event,void * info,int toggle,int tries)391 void Stream::callback(int event, void* info, int toggle, int tries)
392 {
393     int32_t activeStreamIDToRestart = 0;
394     {
395         std::unique_lock lock(mLock);
396         ALOGV("%s track(%p) streamID %d", __func__, mAudioTrack.get(), (int)mStreamID);
397 
398         if (mAudioTrack == nullptr) {
399             // The AudioTrack is either with this stream or its pair.
400             // if this swaps a few times, the toggle is bound to be wrong, so we fail then.
401             //
402             // TODO: Modify AudioTrack callbacks to avoid the hacky toggle and retry
403             // logic here.
404             if (tries < 3) {
405                 lock.unlock();
406                 ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID);
407                 getPairStream()->callback(event, info, toggle, tries + 1);
408             } else {
409                 ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID);
410             }
411             return;
412         }
413         if (mToggle != toggle) {
414             ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID);
415             return;
416         }
417         switch (event) {
418         case AudioTrack::EVENT_MORE_DATA:
419             ALOGW("%s streamID %d Invalid EVENT_MORE_DATA for static track",
420                     __func__, (int)mStreamID);
421             break;
422         case AudioTrack::EVENT_UNDERRUN:
423             ALOGW("%s streamID %d Invalid EVENT_UNDERRUN for static track",
424                     __func__, (int)mStreamID);
425             break;
426         case AudioTrack::EVENT_BUFFER_END:
427             ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID);
428             if (mState != IDLE) {
429                 activeStreamIDToRestart = mStreamID;
430                 mStopTimeNs = systemTime();
431             }
432             break;
433         case AudioTrack::EVENT_LOOP_END:
434             ALOGV("%s streamID %d EVENT_LOOP_END", __func__, (int)mStreamID);
435             break;
436         case AudioTrack::EVENT_NEW_IAUDIOTRACK:
437             ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, (int)mStreamID);
438             break;
439         default:
440             ALOGW("%s streamID %d Invalid event %d", __func__, (int)mStreamID, event);
441             break;
442         }
443     } // lock ends here.  This is on the callback thread, no need to be precise.
444     if (activeStreamIDToRestart > 0) {
445         // Restart only if a particular streamID is still current and active.
446         ALOGV("%s: moveToRestartQueue %d", __func__, activeStreamIDToRestart);
447         mStreamManager->moveToRestartQueue(this, activeStreamIDToRestart);
448     }
449 }
450 
dump() const451 void Stream::dump() const
452 {
453     // TODO: consider std::try_lock() - ok for now for ALOGV.
454     ALOGV("mPairStream=%p, mState=%d, mStreamID=%d, mSoundID=%d, mPriority=%d, mLoop=%d",
455             getPairStream(), mState, (int)getStreamID(), getSoundID(), mPriority, mLoop);
456 }
457 
458 } // namespace android::soundpool
459