• 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,int32_t playerIId)232 Stream* Stream::playPairStream(std::vector<std::any>& garbage, int32_t playerIId) {
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, playerIId);
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,int32_t playerIId)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, int32_t playerIId)
278 {
279     ALOGV("%s(%p)(soundID=%d, streamID=%d, leftVolume=%f, rightVolume=%f,"
280             " priority=%d, loop=%d, rate=%f, playerIId=%d)",
281             __func__, this, sound->getSoundID(), nextStreamID, leftVolume, rightVolume,
282             priority, loop, rate, playerIId);
283 
284     // initialize track
285     const int32_t channelCount = sound->getChannelCount();
286     const auto sampleRate = (uint32_t)lround(double(sound->getSampleRate()) * rate);
287     size_t frameCount = 0;
288 
289     if (loop) {
290         const audio_format_t format = sound->getFormat();
291         const size_t frameSize = audio_is_linear_pcm(format)
292                 ? channelCount * audio_bytes_per_sample(format) : 1;
293         frameCount = sound->getSizeInBytes() / frameSize;
294     }
295 
296     if (mAudioTrack != nullptr) {
297         if (mSoundID == sound->getSoundID()
298                 && mAudioTrack->setSampleRate(sampleRate) == NO_ERROR) {
299             // Reuse the old track if the soundID matches.
300             // the sample rate may fail to change if the audio track is a fast track.
301             ALOGV("%s: reusing track %p for sound %d",
302                     __func__, mAudioTrack.get(), sound->getSoundID());
303         } else {
304             // If reuse not possible, move mAudioTrack to garbage, set to nullptr.
305             garbage.emplace_back(std::move(mAudioTrack));
306             mAudioTrack.clear(); // move should have cleared the sp<>, but we clear just in case.
307         }
308     }
309     if (mAudioTrack == nullptr) {
310         // mToggle toggles each time a track is started on a given stream.
311         // This enables the detection of callbacks received from the old
312         // audio track while the new one is being started and avoids processing them with
313         // wrong audio audio buffer size  (mAudioBufferSize)
314         auto toggle = mToggle ^ 1;
315         // NOLINTNEXTLINE(performance-no-int-to-ptr)
316         audio_channel_mask_t soundChannelMask = sound->getChannelMask();
317         // When sound contains a valid channel mask, use it as is.
318         // Otherwise, use stream count to calculate channel mask.
319         audio_channel_mask_t channelMask = soundChannelMask != AUDIO_CHANNEL_NONE
320                 ? soundChannelMask : audio_channel_out_mask_from_count(channelCount);
321 
322         // do not create a new audio track if current track is compatible with sound parameters
323 
324         android::content::AttributionSourceState attributionSource;
325         attributionSource.packageName = mStreamManager->getOpPackageName();
326         attributionSource.token = sp<BBinder>::make();
327         mCallback =  sp<StreamCallback>::make(this, toggle),
328         // TODO b/182469354 make consistent with AudioRecord, add util for native source
329         mAudioTrack = new AudioTrack(AUDIO_STREAM_DEFAULT, sampleRate, sound->getFormat(),
330                 channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_NONE,
331                 mCallback,
332                 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE,
333                 AudioTrack::TRANSFER_DEFAULT,
334                 nullptr /*offloadInfo*/, attributionSource,
335                 mStreamManager->getAttributes(),
336                 false /*doNotReconnect*/, 1.0f /*maxRequiredSpeed*/);
337         // Set caller name so it can be logged in destructor.
338         // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL
339         mAudioTrack->setCallerName("soundpool");
340 
341         if (playerIId != PLAYER_PIID_INVALID) {
342             mAudioTrack->setPlayerIId(playerIId);
343         }
344 
345         if (status_t status = mAudioTrack->initCheck();
346             status != NO_ERROR) {
347             ALOGE("%s: error %d creating AudioTrack", __func__, status);
348             // TODO: should we consider keeping the soundID and reusing the old track?
349             mState = IDLE;
350             mSoundID = 0;
351             mSound.reset();
352             garbage.emplace_back(std::move(mAudioTrack)); // remove mAudioTrack.
353             mAudioTrack.clear(); // move should have cleared the sp<>, but we clear just in case.
354             return;
355         }
356         // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
357         mToggle = toggle;
358         ALOGV("%s: using new track %p for sound %d",
359                 __func__, mAudioTrack.get(), sound->getSoundID());
360     }
361     if (mMuted) {
362         mAudioTrack->setVolume(0.f, 0.f);
363     } else {
364         mAudioTrack->setVolume(leftVolume, rightVolume);
365     }
366     mAudioTrack->setLoop(0, frameCount, loop);
367     mAudioTrack->start();
368     mSound = sound;
369     mSoundID = sound->getSoundID();
370     mPriority = priority;
371     mLoop = loop;
372     mLeftVolume = leftVolume;
373     mRightVolume = rightVolume;
374     mRate = rate;
375     mState = PLAYING;
376     mStopTimeNs = 0;
377     mStreamID = nextStreamID;  // prefer this to be the last, as it is an atomic sync point
378 }
379 
getCorrespondingStreamID()380 int Stream::getCorrespondingStreamID() {
381     std::lock_guard lock(mLock);
382     return static_cast<int>(mAudioTrack ? mStreamID : getPairStream()->mStreamID);
383 }
384 
onMoreData(const AudioTrack::Buffer &)385 size_t Stream::StreamCallback::onMoreData(const AudioTrack::Buffer&) {
386     ALOGW("%s streamID %d Unexpected EVENT_MORE_DATA for static track",
387             __func__, mStream->getCorrespondingStreamID());
388     return 0;
389 }
390 
onUnderrun()391 void Stream::StreamCallback::onUnderrun() {
392     ALOGW("%s streamID %d Unexpected EVENT_UNDERRUN for static track",
393             __func__, mStream->getCorrespondingStreamID());
394 }
395 
onLoopEnd(int32_t)396 void Stream::StreamCallback::onLoopEnd(int32_t) {
397     ALOGV("%s streamID %d EVENT_LOOP_END", __func__, mStream->getCorrespondingStreamID());
398 }
399 
onMarker(uint32_t)400 void Stream::StreamCallback::onMarker(uint32_t) {
401     ALOGW("%s streamID %d Unexpected EVENT_MARKER for static track",
402             __func__, mStream->getCorrespondingStreamID());
403 }
404 
onNewPos(uint32_t)405 void Stream::StreamCallback::onNewPos(uint32_t) {
406     ALOGW("%s streamID %d Unexpected EVENT_NEW_POS for static track",
407             __func__, mStream->getCorrespondingStreamID());
408 }
409 
onBufferEnd()410 void Stream::StreamCallback::onBufferEnd() {
411     mStream->onBufferEnd(mToggle, 0);
412 }
413 
onNewIAudioTrack()414 void Stream::StreamCallback::onNewIAudioTrack() {
415     ALOGV("%s streamID %d NEW_IAUDIOTRACK", __func__, mStream->getCorrespondingStreamID());
416 }
417 
onStreamEnd()418 void Stream::StreamCallback::onStreamEnd() {
419     ALOGW("%s streamID %d Unexpected EVENT_STREAM_END for static track",
420             __func__, mStream->getCorrespondingStreamID());
421 }
422 
onCanWriteMoreData(const AudioTrack::Buffer &)423 size_t Stream::StreamCallback::onCanWriteMoreData(const AudioTrack::Buffer&) {
424     ALOGW("%s streamID %d Unexpected EVENT_CAN_WRITE_MORE_DATA for static track",
425             __func__, mStream->getCorrespondingStreamID());
426     return 0;
427 }
428 
onBufferEnd(int toggle,int tries)429 void Stream::onBufferEnd(int toggle, int tries)
430 {
431     int32_t activeStreamIDToRestart = 0;
432     {
433         std::unique_lock lock(mLock);
434         ALOGV("%s track(%p) streamID %d", __func__, mAudioTrack.get(), (int)mStreamID);
435 
436         if (mAudioTrack == nullptr) {
437             // The AudioTrack is either with this stream or its pair.
438             // if this swaps a few times, the toggle is bound to be wrong, so we fail then.
439             //
440             // TODO: Modify AudioTrack callbacks to avoid the hacky toggle and retry
441             // logic here.
442             if (tries < 3) {
443                 lock.unlock();
444                 ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID);
445                 getPairStream()->onBufferEnd(toggle, tries + 1);
446             } else {
447                 ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID);
448             }
449             return;
450         }
451         if (mToggle != toggle) {
452             ALOGD("%s streamID %d wrong toggle", __func__, (int)mStreamID);
453             return;
454         }
455         ALOGV("%s streamID %d EVENT_BUFFER_END", __func__, (int)mStreamID);
456         if (mState != IDLE) {
457             activeStreamIDToRestart = mStreamID;
458             mStopTimeNs = systemTime();
459         }
460     } // lock ends here.  This is on the callback thread, no need to be precise.
461     if (activeStreamIDToRestart > 0) {
462         // Restart only if a particular streamID is still current and active.
463         ALOGV("%s: moveToRestartQueue %d", __func__, activeStreamIDToRestart);
464         mStreamManager->moveToRestartQueue(this, activeStreamIDToRestart);
465     }
466 }
467 
dump() const468 void Stream::dump() const
469 {
470     // TODO: consider std::try_lock() - ok for now for ALOGV.
471     ALOGV("mPairStream=%p, mState=%d, mStreamID=%d, mSoundID=%d, mPriority=%d, mLoop=%d",
472             getPairStream(), mState, (int)getStreamID(), getSoundID(), mPriority, mLoop);
473 }
474 
475 } // namespace android::soundpool
476