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