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